From f5cf9d904f19475ea5c162684907b166f23f6591 Mon Sep 17 00:00:00 2001 From: Vitaliy K Date: Sun, 10 Jan 2021 17:48:34 -0500 Subject: [PATCH 01/13] Simplify Entity and Repository structure (#233) * BREAKING: Entity/Repository cleanup, see #231 * Rename IEntityWithTypedId to IEntity * Remove Entity, replace EnitytWithTypedId with Entity * Remove Reference to Newtonsoft.Json from SharpArch.Domain see #232 --- Directory.Build.props | 5 +- .../Src/Suteki.TardisBank.Domain/Account.cs | 4 +- .../Suteki.TardisBank.Domain/Announcement.cs | 2 +- .../Src/Suteki.TardisBank.Domain/Message.cs | 4 +- .../PaymentSchedule.cs | 4 +- .../Suteki.TardisBank.Domain/Transaction.cs | 4 +- .../Src/Suteki.TardisBank.Domain/User.cs | 4 +- .../AutoPersistenceModelGenerator.cs | 5 +- .../AutomappingConfiguration.cs | 5 +- .../Suteki.TardisBank.Tasks/UserService.cs | 6 +- .../Model/ChildTests.cs | 5 +- .../Model/MessageTests.cs | 3 +- .../Model/ParentTests.cs | 5 +- .../Controllers/AnnouncementsController.cs | 4 +- .../Src/Suteki.TardisBank.WebApi/Startup.cs | 15 +- SharpArch.AutoLoad.DotSettings | 1 + .../DomainModel/BaseObjectEqualityComparer.cs | 2 +- .../DomainModel/DomainSignatureAttribute.cs | 6 +- Src/SharpArch.Domain/DomainModel/Entity.cs | 166 +++++++++++++++-- .../DomainModel/EntityWithTypedId.cs | 159 ---------------- Src/SharpArch.Domain/DomainModel/IEntity.cs | 17 +- .../DomainModel/IEntityWithTypedId.cs | 20 --- .../DomainModel/IHasAssignedId.cs | 4 +- Src/SharpArch.Domain/Enums.cs | 13 +- .../PersistenceSupport/IAsyncRepository.cs | 18 -- .../IEntityDuplicateChecker.cs | 2 +- .../PersistenceSupport/ILinqRepository.cs | 54 +++++- .../ILinqRepositoryWithTypedId.cs | 54 ------ ...epositoryWithTypedId.cs => IRepository.cs} | 31 ++-- .../RepositoryExtensions.cs | 8 +- Src/SharpArch.Domain/SharpArch.Domain.csproj | 1 - .../NHibernateRegistrationExtensions.cs | 6 +- ...ithTypedId.cs => INHibernateRepository.cs} | 29 +-- .../EntityDuplicateChecker.cs | 2 +- .../AutomappingConfiguration.cs | 8 +- Src/SharpArch.NHibernate/LinqRepository.cs | 52 +++++- .../LinqRepositoryWithTypedId.cs | 56 ------ .../NHibernateRepository.cs | 32 ++-- ...TypedId.cs => NHibernateRepositoryBase.cs} | 104 +++++------ .../TransactionManager.cs | 2 +- .../Repositories/IRavenDbRepository.cs | 59 +++++- .../IRavenDbRepositoryWithTypedId.cs | 62 ------- Src/SharpArch.RavenDb/RavenDbRepository.cs | 165 +++++++++++++++-- .../RavenDbRepositoryWithTypedId.cs | 169 ------------------ .../NHibernate/RepositoryTestsBase.cs | 1 + .../TransientDatabaseTests.cs | 1 + .../Helpers/EntityIdSetter.cs | 10 +- .../Mappings/AutoPersistenceModelGenerator.cs | 3 +- .../RepositoryTests.cs | 8 +- .../TestsPersistenceModelGenerator.cs | 3 +- .../NHibernateRepositoryTests.cs | 6 +- .../NHibernateTestsSetup.cs | 2 +- .../RepositoryTests.cs | 8 +- .../HasUniqueEntitySignatureValidatorTests.cs | 8 +- .../BaseObjectEqualityComparerTests.cs | 6 +- .../DomainModel/EntityTests.cs | 75 +++----- .../SharpArch.Domain/TestEntities.cs | 24 +-- VersionHistory.txt | 9 + 58 files changed, 707 insertions(+), 834 deletions(-) delete mode 100644 Src/SharpArch.Domain/DomainModel/EntityWithTypedId.cs delete mode 100644 Src/SharpArch.Domain/DomainModel/IEntityWithTypedId.cs delete mode 100644 Src/SharpArch.Domain/PersistenceSupport/IAsyncRepository.cs delete mode 100644 Src/SharpArch.Domain/PersistenceSupport/ILinqRepositoryWithTypedId.cs rename Src/SharpArch.Domain/PersistenceSupport/{IAsyncRepositoryWithTypedId.cs => IRepository.cs} (74%) rename Src/SharpArch.NHibernate/Contracts/Repositories/{IAsynNHibernatecRepositoryWithTypedId.cs => INHibernateRepository.cs} (83%) delete mode 100644 Src/SharpArch.NHibernate/LinqRepositoryWithTypedId.cs rename Src/SharpArch.NHibernate/{NHibernateRepositoryWithTypedId.cs => NHibernateRepositoryBase.cs} (60%) delete mode 100644 Src/SharpArch.RavenDb/Contracts/Repositories/IRavenDbRepositoryWithTypedId.cs delete mode 100644 Src/SharpArch.RavenDb/RavenDbRepositoryWithTypedId.cs diff --git a/Directory.Build.props b/Directory.Build.props index 748c48d83..319465834 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -33,10 +33,7 @@ https://github.com/sharparchitecture/Sharp-Architecture/raw/master/Artefacts/Documentation/icon.png http://sharparchitecture.github.io/ false - https://github.com/sharparchitecture/Sharp-Architecture/releases/tag/6.1.1 - true - True - snupkg + https://github.com/sharparchitecture/Sharp-Architecture/releases/tag/7.0.0 sharp-architecture;sharp-arch diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Account.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Account.cs index 3068e64ab..4eaa1e1d5 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Account.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Account.cs @@ -6,7 +6,7 @@ namespace Suteki.TardisBank.Domain using SharpArch.Domain.DomainModel; - public class Account : Entity + public class Account : Entity { public const int MaxTransactions = 100; public virtual decimal OldTransactionsBalance { get; protected set; } @@ -66,4 +66,4 @@ public virtual void RemovePaymentSchedule(int paymentScheduleId) this.PaymentSchedules.Remove(scheduleToRemove); } } -} \ No newline at end of file +} diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Announcement.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Announcement.cs index ce14a09db..19b1c922a 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Announcement.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Announcement.cs @@ -6,7 +6,7 @@ using SharpArch.Domain.DomainModel; [DebuggerDisplay("{Id}: {Title}")] - public class Announcement: Entity + public class Announcement: Entity { public virtual DateTime Date { get; set; } diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Message.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Message.cs index 469d9030b..95428e467 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Message.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Message.cs @@ -4,7 +4,7 @@ namespace Suteki.TardisBank.Domain using SharpArch.Domain.DomainModel; - public class Message : Entity + public class Message : Entity { public Message(DateTime date, string text, User user) { @@ -30,4 +30,4 @@ public virtual void Read() public virtual bool HasBeenRead { get; protected set; } } -} \ No newline at end of file +} diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/PaymentSchedule.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/PaymentSchedule.cs index bb82226c9..4cee6cc29 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/PaymentSchedule.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/PaymentSchedule.cs @@ -4,7 +4,7 @@ using SharpArch.Domain.DomainModel; - public class PaymentSchedule : Entity + public class PaymentSchedule : Entity { public PaymentSchedule(DateTime nextRun, Interval interval, decimal amount, string description, Account account) { @@ -42,4 +42,4 @@ public virtual void CalculateNextRunDate() } } } -} \ No newline at end of file +} diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Transaction.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Transaction.cs index b0e241ab9..d49c04013 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Transaction.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Transaction.cs @@ -4,7 +4,7 @@ namespace Suteki.TardisBank.Domain using SharpArch.Domain.DomainModel; - public class Transaction : Entity + public class Transaction : Entity { public Transaction(string description, decimal amount, Account account) { @@ -25,4 +25,4 @@ protected Transaction() public virtual DateTime Date { get; protected set; } } -} \ No newline at end of file +} diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/User.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/User.cs index 42714c2bd..f7cdd5602 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/User.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/User.cs @@ -24,7 +24,7 @@ public static class UserRoles public const string Parent = "Parent"; } - public abstract class User : Entity + public abstract class User : Entity { public const int MaxMessages = 20; @@ -94,4 +94,4 @@ public virtual string[] GetRoles() return new string[0]; } } -} \ No newline at end of file +} diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Infrastructure/NHibernateMaps/AutoPersistenceModelGenerator.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Infrastructure/NHibernateMaps/AutoPersistenceModelGenerator.cs index 1e3c07b86..e28299542 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Infrastructure/NHibernateMaps/AutoPersistenceModelGenerator.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Infrastructure/NHibernateMaps/AutoPersistenceModelGenerator.cs @@ -9,15 +9,14 @@ namespace Suteki.TardisBank.Infrastructure.NHibernateMaps { /// - /// Generates the automapping for the domain assembly + /// Generates the auto-mapping for the domain assembly /// public class AutoPersistenceModelGenerator : IAutoPersistenceModelGenerator { public AutoPersistenceModel Generate() { var mappings = AutoMap.AssemblyOf(new AutomappingConfiguration()); - mappings.IgnoreBase(); - mappings.IgnoreBase(typeof(EntityWithTypedId<>)); + mappings.IgnoreBase(typeof(Entity<>)); mappings.Conventions.Setup(GetConventions()); mappings.UseOverridesFromAssemblyOf(); diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Infrastructure/NHibernateMaps/AutomappingConfiguration.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Infrastructure/NHibernateMaps/AutomappingConfiguration.cs index ade249ed5..5110b7b73 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Infrastructure/NHibernateMaps/AutomappingConfiguration.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Infrastructure/NHibernateMaps/AutomappingConfiguration.cs @@ -12,8 +12,7 @@ public class AutomappingConfiguration : DefaultAutomappingConfiguration /// public override bool ShouldMap(System.Type type) { - return type.GetInterfaces().Any(x => - x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IEntityWithTypedId<>)); + return type.GetInterfaces().Any(x => x == typeof(IEntity)); } /// @@ -26,7 +25,7 @@ public override bool ShouldMap(Member member) /// public override bool AbstractClassIsLayerSupertype(System.Type type) { - return type == typeof(EntityWithTypedId<>) || type == typeof(Entity); + return type == typeof(Entity<>); } } diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Tasks/UserService.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Tasks/UserService.cs index ee465943b..6baca1736 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Tasks/UserService.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Tasks/UserService.cs @@ -14,11 +14,11 @@ public class UserService : IUserService { readonly IHttpContextService _context; - readonly ILinqRepository _parentRepository; + readonly ILinqRepository _parentRepository; - readonly ILinqRepository _userRepository; + readonly ILinqRepository _userRepository; - public UserService(IHttpContextService context, ILinqRepository parentRepository, ILinqRepository userRepository) + public UserService(IHttpContextService context, ILinqRepository parentRepository, ILinqRepository userRepository) { _context = context; _parentRepository = parentRepository; diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/ChildTests.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/ChildTests.cs index 03e71f5be..8a11b2cce 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/ChildTests.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/ChildTests.cs @@ -5,13 +5,14 @@ namespace Suteki.TardisBank.Tests.Model using Domain; using FluentAssertions; using SharpArch.NHibernate; + using SharpArch.NHibernate.Impl; using SharpArch.Testing.Xunit.NHibernate; using Xunit; public class ChildTests : TransientDatabaseTests { - readonly LinqRepository _childRepository; + readonly LinqRepository _childRepository; int _childId; int _parentId; @@ -19,7 +20,7 @@ public class ChildTests : TransientDatabaseTests public ChildTests(TransientDatabaseSetup dbSetup) : base(dbSetup) { - _childRepository = new LinqRepository(TransactionManager); + _childRepository = new LinqRepository(TransactionManager); } protected override void LoadTestData() diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/MessageTests.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/MessageTests.cs index f1982bcd4..749755485 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/MessageTests.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/MessageTests.cs @@ -6,6 +6,7 @@ namespace Suteki.TardisBank.Tests.Model using MediatR; using Moq; using SharpArch.NHibernate; + using SharpArch.NHibernate.Impl; using SharpArch.Testing.NHibernate; using SharpArch.Testing.Xunit.NHibernate; using Xunit; @@ -33,7 +34,7 @@ protected override void LoadTestData() [Fact] public async Task Should_be_able_to_add_a_message_to_a_user() { - var parentRepository = new LinqRepository(TransactionManager); + var parentRepository = new LinqRepository(TransactionManager); User userToTestWith = await parentRepository.GetAsync(_userId); userToTestWith.SendMessage("some message", _mediator.Object); diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/ParentTests.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/ParentTests.cs index 5eda6fe74..a69f4a1fe 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/ParentTests.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/ParentTests.cs @@ -4,6 +4,7 @@ namespace Suteki.TardisBank.Tests.Model using Domain; using FluentAssertions; using SharpArch.NHibernate; + using SharpArch.NHibernate.Impl; using SharpArch.Testing.Xunit.NHibernate; using Xunit; @@ -28,7 +29,7 @@ protected override void LoadTestData() [Fact] public async Task Should_be_able_to_add_a_child_to_a_parent() { - var linqRepository = new LinqRepository(TransactionManager); + var linqRepository = new LinqRepository(TransactionManager); Parent savedParent = await linqRepository.GetAsync(_parentId); savedParent.Should().NotBeNull(); @@ -48,7 +49,7 @@ public async Task Should_be_able_to_add_a_child_to_a_parent() [Fact] public async Task Should_be_able_to_create_and_retrieve_Parent() { - Parent parent = await new LinqRepository(TransactionManager).GetAsync(_parentId); + Parent parent = await new LinqRepository(TransactionManager).GetAsync(_parentId); parent.Should().NotBeNull(); parent.Name.Should().Be("Mike Hadlow"); parent.UserName.Should().Be("mike@yahoo.com"); diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.WebApi/Controllers/AnnouncementsController.cs b/Samples/TardisBank/Src/Suteki.TardisBank.WebApi/Controllers/AnnouncementsController.cs index 11b6d830d..d2e0379e4 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.WebApi/Controllers/AnnouncementsController.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.WebApi/Controllers/AnnouncementsController.cs @@ -22,7 +22,7 @@ [Transaction(IsolationLevel.ReadCommitted)] public class AnnouncementsController : ControllerBase { - readonly ILinqRepository _announcementRepository; + readonly ILinqRepository _announcementRepository; #if NETCOREAPP3_1 || NET5_0 [NotNull] readonly LinkGenerator _linkGenerator; #endif @@ -32,7 +32,7 @@ public class AnnouncementsController : ControllerBase /// Creates AnnouncementController. /// /// Announcements repository. - public AnnouncementsController([NotNull] ILinqRepository announcementRepository, + public AnnouncementsController([NotNull] ILinqRepository announcementRepository, #if NETCOREAPP3_1 || NET5_0 LinkGenerator linkGenerator, #endif diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.WebApi/Startup.cs b/Samples/TardisBank/Src/Suteki.TardisBank.WebApi/Startup.cs index 82d731f93..c381c0721 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.WebApi/Startup.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.WebApi/Startup.cs @@ -15,6 +15,7 @@ namespace Suteki.TardisBank.WebApi using SharpArch.Domain.PersistenceSupport; using SharpArch.NHibernate; using SharpArch.NHibernate.Extensions.DependencyInjection; + using SharpArch.NHibernate.Impl; using SharpArch.Web.AspNetCore.Transaction; #if NETCOREAPP2_1 || NETCOREAPP2_2 @@ -110,11 +111,11 @@ public void ConfigureContainer(ContainerBuilder builder) .SingleInstance(); builder.RegisterAssemblyTypes(typeof(AccountMap).Assembly) - .AsClosedTypesOf(typeof(IAsyncRepositoryWithTypedId<,>)) + .AsClosedTypesOf(typeof(IRepository<,>)) #if DEBUG .Where(t => { - var x = t.IsClosedTypeOf(typeof(IAsyncRepositoryWithTypedId<,>)); + var x = t.IsClosedTypeOf(typeof(IRepository<,>)); _logger.Information("{type}, register: {register}", t, x); return x; }) @@ -122,16 +123,10 @@ public void ConfigureContainer(ContainerBuilder builder) .AsImplementedInterfaces() .InstancePerLifetimeScope(); - builder.RegisterGeneric(typeof(NHibernateRepositoryWithTypedId<,>)) + builder.RegisterGeneric(typeof(NHibernateRepository<,>)) .AsImplementedInterfaces() .InstancePerLifetimeScope(); - builder.RegisterGeneric(typeof(NHibernateRepository<>)) - .AsImplementedInterfaces() - .InstancePerLifetimeScope(); - builder.RegisterGeneric(typeof(LinqRepositoryWithTypedId<,>)) - .AsImplementedInterfaces() - .InstancePerLifetimeScope(); - builder.RegisterGeneric(typeof(LinqRepository<>)) + builder.RegisterGeneric(typeof(LinqRepository<,>)) .AsImplementedInterfaces() .InstancePerLifetimeScope(); } diff --git a/SharpArch.AutoLoad.DotSettings b/SharpArch.AutoLoad.DotSettings index 26a3609c0..8dd6f407e 100644 --- a/SharpArch.AutoLoad.DotSettings +++ b/SharpArch.AutoLoad.DotSettings @@ -428,6 +428,7 @@ FluentAssertions.AssertionExtensions.Should($EXPR$).NotBeNull() True True + True True diff --git a/Src/SharpArch.Domain/DomainModel/BaseObjectEqualityComparer.cs b/Src/SharpArch.Domain/DomainModel/BaseObjectEqualityComparer.cs index 58a265e4a..850902705 100644 --- a/Src/SharpArch.Domain/DomainModel/BaseObjectEqualityComparer.cs +++ b/Src/SharpArch.Domain/DomainModel/BaseObjectEqualityComparer.cs @@ -10,7 +10,7 @@ /// /// /// This may be used for comparing objects of type and anything - /// that derives from it, such as and . + /// that derives from it, such as and . /// /// /// NOTE: Microsoft decided that set operators such as Intersect, Union and Distinct should diff --git a/Src/SharpArch.Domain/DomainModel/DomainSignatureAttribute.cs b/Src/SharpArch.Domain/DomainModel/DomainSignatureAttribute.cs index 6277968a8..5d3aadab0 100644 --- a/Src/SharpArch.Domain/DomainModel/DomainSignatureAttribute.cs +++ b/Src/SharpArch.Domain/DomainModel/DomainSignatureAttribute.cs @@ -5,15 +5,15 @@ namespace SharpArch.Domain.DomainModel /// /// Facilitates indicating which property(s) describe the unique signature of an - /// entity. See Entity.GetTypeSpecificSignatureProperties() for when this is leveraged. + /// entity. See for when this is leveraged. /// /// - /// This is intended for use with . It may NOT be used on a . + /// This is intended for use with . It may NOT be used on a . /// [Serializable] [AttributeUsage(AttributeTargets.Property)] [PublicAPI] - [BaseTypeRequired(typeof(IEntityWithTypedId<>))] + [BaseTypeRequired(typeof(IEntity<>))] public sealed class DomainSignatureAttribute : Attribute { } } diff --git a/Src/SharpArch.Domain/DomainModel/Entity.cs b/Src/SharpArch.Domain/DomainModel/Entity.cs index 6f9430616..6b07131a3 100644 --- a/Src/SharpArch.Domain/DomainModel/Entity.cs +++ b/Src/SharpArch.Domain/DomainModel/Entity.cs @@ -1,20 +1,164 @@ -namespace SharpArch.Domain.DomainModel +namespace SharpArch.Domain.DomainModel { using System; + using System.Diagnostics.CodeAnalysis; + using System.Linq; + using System.Reflection; + using System.Xml.Serialization; using JetBrains.Annotations; /// - /// Provides a base class for your objects which will be persisted to the database. + /// For a discussion of this object, see + /// http://devlicio.us/blogs/billy_mccafferty/archive/2007/04/25/using-equals-gethashcode-effectively.aspx /// - /// - /// Benefits include the addition of an Id property along with a consistent manner for - /// comparing entities. - /// Since nearly all of the entities you create will have a type of int Id, this - /// base class leverages this assumption. If you want an entity with a type other - /// than int, such as string, then use instead. - /// [Serializable] [PublicAPI] - public abstract class Entity : EntityWithTypedId - { } + public abstract class Entity : ValidatableObject, IEntity, IEntity, + IEquatable> + where TId : IEquatable + { + /// + /// To help ensure hash code uniqueness, a carefully selected random number multiplier + /// is used within the calculation. Goodrich and Tamassia's Data Structures and + /// Algorithms in Java asserts that 31, 33, 37, 39 and 41 will produce the fewest number + /// of collisions. See http://computinglife.wordpress.com/2008/11/20/why-do-hash-functions-use-prime-numbers/ + /// for more information. + /// + const int HashMultiplier = 31; + + int? _cachedHashcode; + + /// + /// Gets or sets the ID. + /// + /// + /// + /// The ID may be of type string, int, a custom type, etc. + /// The setter is protected to allow unit tests to set this property via reflection + /// and to allow domain objects more flexibility in setting this for those objects + /// with assigned IDs. It's virtual to allow NHibernate-backed objects to be lazily + /// loaded. This is ignored for XML serialization because it does not have a public + /// setter (which is very much by design). See the FAQ within the documentation if + /// you'd like to have the ID XML serialized. + /// + /// + [XmlIgnore] + public virtual TId Id { get; protected set; } + + /// + public virtual object GetId() + => Id.Equals(default(TId)) ? (object)null : Id; + + /// + /// Returns a value indicating whether the current object is transient. + /// + /// + /// Transient objects are not associated with an item already in storage. For instance, + /// a Customer is transient if its ID is 0. It's virtual to allow NHibernate-backed + /// objects to be lazily loaded. + /// + public virtual bool IsTransient() + { + if (!(Id is object)) return true; + return Id.Equals(default(TId)); + } + + /// + public virtual bool Equals(Entity other) + { + if (ReferenceEquals(this, other)) { + return true; + } + + if (other == null || GetType() != other.GetTypeUnproxied()) { + return false; + } + + if (HasSameNonDefaultIdAs(other)) { + return true; + } + + // Since the Ids aren't the same, both of them must be transient to + // compare domain signatures; because if one is transient and the + // other is a persisted entity, then they cannot be the same object. + return IsTransient() && other.IsTransient() && HasSameObjectSignatureAs(other); + + } + + /// + /// Determines whether the specified is equal to this instance. + /// + /// The to compare with the current . + /// true if the specified is equal to this instance; otherwise, false. + public override bool Equals(object obj) + { + var compareTo = obj as Entity; + return Equals(compareTo); + } + + /// + /// Returns a hash code for this instance. + /// + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + /// + /// This is used to provide the hash code identifier of an object using the signature + /// properties of the object; although it's necessary for NHibernate's use, this can + /// also be useful for business logic purposes and has been included in this base + /// class, accordingly. Since it is recommended that GetHashCode change infrequently, + /// if at all, in an object's lifetime, it's important that properties are carefully + /// selected which truly represent the signature of an object. + /// + [SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")] + public override int GetHashCode() + { + if (_cachedHashcode.HasValue) { + return _cachedHashcode.Value; + } + + if (IsTransient()) { + _cachedHashcode = base.GetHashCode(); + } + else { + unchecked { + // It's possible for two objects to return the same hash code based on + // identically valued properties, even if they're of two different types, + // so we include the object's type in the hash calculation + int hashCode = GetType().GetHashCode(); + _cachedHashcode = (hashCode * HashMultiplier) ^ Id.GetHashCode(); + } + } + + return _cachedHashcode.Value; + } + + /// + /// Returns the signature properties that are specific to the type of the current object. + /// + /// + /// If you choose NOT to override this method (which will be the most common scenario), + /// then you should decorate the appropriate property(s) with the + /// attribute and they will be compared automatically. This is the preferred method of + /// managing the domain signature of entity objects. This ensures that the entity has at + /// least one property decorated with the attribute. + /// + protected override PropertyInfo[] GetTypeSpecificSignatureProperties() + { + return + GetType().GetProperties().Where(p => p.IsDefined(typeof (DomainSignatureAttribute), true)).ToArray(); + + } + + /// + /// Returns a value indicating whether the current entity and the provided entity have + /// the same ID values and the IDs are not of the default ID value. + /// + /// + /// true if the current entity and the provided entity have the same ID values and the IDs are not of the + /// default ID value; otherwise; false. + /// + bool HasSameNonDefaultIdAs(Entity compareTo) + { + return !IsTransient() && !compareTo.IsTransient() && Id.Equals(compareTo.Id); + } + } } diff --git a/Src/SharpArch.Domain/DomainModel/EntityWithTypedId.cs b/Src/SharpArch.Domain/DomainModel/EntityWithTypedId.cs deleted file mode 100644 index 956b45a9e..000000000 --- a/Src/SharpArch.Domain/DomainModel/EntityWithTypedId.cs +++ /dev/null @@ -1,159 +0,0 @@ -namespace SharpArch.Domain.DomainModel -{ - using System; - using System.Diagnostics.CodeAnalysis; - using System.Linq; - using System.Reflection; - using System.Xml.Serialization; - using JetBrains.Annotations; - using Newtonsoft.Json; - - /// - /// For a discussion of this object, see - /// http://devlicio.us/blogs/billy_mccafferty/archive/2007/04/25/using-equals-gethashcode-effectively.aspx - /// - [Serializable] - [PublicAPI] - public abstract class EntityWithTypedId : ValidatableObject, IEntityWithTypedId, IEntity - where TId : IEquatable - { - /// - /// To help ensure hash code uniqueness, a carefully selected random number multiplier - /// is used within the calculation. Goodrich and Tamassia's Data Structures and - /// Algorithms in Java asserts that 31, 33, 37, 39 and 41 will produce the fewest number - /// of collisions. See http://computinglife.wordpress.com/2008/11/20/why-do-hash-functions-use-prime-numbers/ - /// for more information. - /// - private const int HashMultiplier = 31; - - private int? cachedHashcode; - - /// - /// Gets or sets the ID. - /// - /// - /// - /// The ID may be of type string, int, a custom type, etc. - /// The setter is protected to allow unit tests to set this property via reflection - /// and to allow domain objects more flexibility in setting this for those objects - /// with assigned IDs. It's virtual to allow NHibernate-backed objects to be lazily - /// loaded. This is ignored for XML serialization because it does not have a public - /// setter (which is very much by design). See the FAQ within the documentation if - /// you'd like to have the ID XML serialized. - /// - /// - [XmlIgnore] - [JsonProperty] - public virtual TId Id { get; protected set; } - - /// - public virtual object GetId() - => Id.Equals(default(TId)) ? (object)null : Id; - - /// - /// Returns a value indicating whether the current object is transient. - /// - /// - /// Transient objects are not associated with an item already in storage. For instance, - /// a Customer is transient if its ID is 0. It's virtual to allow NHibernate-backed - /// objects to be lazily loaded. - /// - public virtual bool IsTransient() - { - if (!(Id is object)) return true; - return Id.Equals(default(TId)); - } - - /// - /// Determines whether the specified is equal to this instance. - /// - /// The to compare with the current . - /// true if the specified is equal to this instance; otherwise, false. - public override bool Equals(object obj) - { - var compareTo = obj as EntityWithTypedId; - - if (ReferenceEquals(this, compareTo)) { - return true; - } - - if (compareTo == null || GetType() != compareTo.GetTypeUnproxied()) { - return false; - } - - if (HasSameNonDefaultIdAs(compareTo)) { - return true; - } - - // Since the Ids aren't the same, both of them must be transient to - // compare domain signatures; because if one is transient and the - // other is a persisted entity, then they cannot be the same object. - return IsTransient() && compareTo.IsTransient() && HasSameObjectSignatureAs(compareTo); - } - - /// - /// Returns a hash code for this instance. - /// - /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. - /// - /// This is used to provide the hash code identifier of an object using the signature - /// properties of the object; although it's necessary for NHibernate's use, this can - /// also be useful for business logic purposes and has been included in this base - /// class, accordingly. Since it is recommended that GetHashCode change infrequently, - /// if at all, in an object's lifetime, it's important that properties are carefully - /// selected which truly represent the signature of an object. - /// - [SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")] - public override int GetHashCode() - { - if (cachedHashcode.HasValue) { - return cachedHashcode.Value; - } - - if (IsTransient()) { - cachedHashcode = base.GetHashCode(); - } - else { - unchecked { - // It's possible for two objects to return the same hash code based on - // identically valued properties, even if they're of two different types, - // so we include the object's type in the hash calculation - int hashCode = GetType().GetHashCode(); - cachedHashcode = (hashCode * HashMultiplier) ^ Id.GetHashCode(); - } - } - - return cachedHashcode.Value; - } - - /// - /// Returns the signature properties that are specific to the type of the current object. - /// - /// - /// If you choose NOT to override this method (which will be the most common scenario), - /// then you should decorate the appropriate property(s) with the - /// attribute and they will be compared automatically. This is the preferred method of - /// managing the domain signature of entity objects. This ensures that the entity has at - /// least one property decorated with the attribute. - /// - protected override PropertyInfo[] GetTypeSpecificSignatureProperties() - { - return - this.GetType().GetProperties().Where(p => p.IsDefined(typeof (DomainSignatureAttribute), true)).ToArray(); - - } - - /// - /// Returns a value indicating whether the current entity and the provided entity have - /// the same ID values and the IDs are not of the default ID value. - /// - /// - /// true if the current entity and the provided entity have the same ID values and the IDs are not of the - /// default ID value; otherwise; false. - /// - private bool HasSameNonDefaultIdAs(EntityWithTypedId compareTo) - { - return !IsTransient() && !compareTo.IsTransient() && Id.Equals(compareTo.Id); - } - } -} diff --git a/Src/SharpArch.Domain/DomainModel/IEntity.cs b/Src/SharpArch.Domain/DomainModel/IEntity.cs index 80b5f5e2d..9259d3af0 100644 --- a/Src/SharpArch.Domain/DomainModel/IEntity.cs +++ b/Src/SharpArch.Domain/DomainModel/IEntity.cs @@ -17,7 +17,7 @@ public interface IEntity /// Entity identifier or null for transient entities. /// /// Calling this method may result in boxing for entities with value type identifier. - /// Use where possible. + /// Use where possible. /// [CanBeNull] object GetId(); @@ -57,4 +57,19 @@ public interface IEntity /// Type GetTypeUnproxied(); } + + /// + /// This serves as a base interface for . + /// It also provides a simple means to develop your own base entity. + /// + [PublicAPI] + public interface IEntity + where TId : IEquatable + { + /// + /// Gets the ID which uniquely identifies the entity instance within its type's bounds. + /// + TId Id { get; } + } + } diff --git a/Src/SharpArch.Domain/DomainModel/IEntityWithTypedId.cs b/Src/SharpArch.Domain/DomainModel/IEntityWithTypedId.cs deleted file mode 100644 index 643cf27f4..000000000 --- a/Src/SharpArch.Domain/DomainModel/IEntityWithTypedId.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace SharpArch.Domain.DomainModel -{ - using System; - using JetBrains.Annotations; - - - /// - /// This serves as a base interface for and - /// . It also provides a simple means to develop your own base entity. - /// - [PublicAPI] - public interface IEntityWithTypedId - where TId : IEquatable - { - /// - /// Gets the ID which uniquely identifies the entity instance within its type's bounds. - /// - TId Id { get; } - } -} diff --git a/Src/SharpArch.Domain/DomainModel/IHasAssignedId.cs b/Src/SharpArch.Domain/DomainModel/IHasAssignedId.cs index 0b461cd50..4341eab09 100644 --- a/Src/SharpArch.Domain/DomainModel/IHasAssignedId.cs +++ b/Src/SharpArch.Domain/DomainModel/IHasAssignedId.cs @@ -1,5 +1,6 @@ namespace SharpArch.Domain.DomainModel { + using System; using JetBrains.Annotations; /// @@ -8,12 +9,13 @@ /// The type of the ID. [PublicAPI] public interface IHasAssignedId + where TId : IEquatable { /// /// Sets the assigned ID of an object. /// /// - /// This is not part of since most entities do not have assigned + /// This is not part of since most entities do not have assigned /// IDs and since business rules will certainly vary as to what constitutes a valid, /// assigned ID for one object but not for another. /// diff --git a/Src/SharpArch.Domain/Enums.cs b/Src/SharpArch.Domain/Enums.cs index 215a4b742..ec744b76d 100644 --- a/Src/SharpArch.Domain/Enums.cs +++ b/Src/SharpArch.Domain/Enums.cs @@ -2,6 +2,7 @@ { using JetBrains.Annotations; + /// /// Contains global enumerations. /// @@ -15,37 +16,37 @@ public static class Enums /// Further information concerning lock modes may be found at: /// http://docs.jboss.org/hibernate/orm/4.1/manual/en-US/html/ch13.html#transactions-locking /// - public enum LockMode + public enum LockMode : byte { /// /// Represents the absence of a lock. All objects switch to this lock mode at the /// end of a Transaction. Objects associated with the session via a call to /// update() or saveOrUpdate() also start out in this lock mode. /// - None, + None = 0, /// /// This lock mode is acquired automatically when data is read under Repeatable Read /// or Serializable isolation level. It can be re-acquired by explicit user request. /// - Read, + Read = 1, /// /// This lock mode can be acquired upon explicit user request using /// SELECT ... FOR UPDATE on databases which support that syntax. /// - Upgrade, + Upgrade = 2, /// /// This lock mode can be acquired upon explicit user request using a /// SELECT ... FOR UPDATE NOWAIT under Oracle. /// - UpgradeNoWait, + UpgradeNoWait = 3, /// /// This lock mode is acquired automatically when a row is updated or inserted. /// - Write + Write = 4 } } } diff --git a/Src/SharpArch.Domain/PersistenceSupport/IAsyncRepository.cs b/Src/SharpArch.Domain/PersistenceSupport/IAsyncRepository.cs deleted file mode 100644 index bd99b17bd..000000000 --- a/Src/SharpArch.Domain/PersistenceSupport/IAsyncRepository.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace SharpArch.Domain.PersistenceSupport -{ - using JetBrains.Annotations; - - /// - /// Provides a standard interface for DAOs which are data-access mechanism agnostic. - /// - /// - /// Since nearly all of the domain objects you create will have a type of int ID, this - /// base DAO leverages this assumption. If you want an entity with a type - /// other than int, such as string, then use . - /// - [PublicAPI] - - public interface IAsyncRepository : IAsyncRepositoryWithTypedId - { - } -} \ No newline at end of file diff --git a/Src/SharpArch.Domain/PersistenceSupport/IEntityDuplicateChecker.cs b/Src/SharpArch.Domain/PersistenceSupport/IEntityDuplicateChecker.cs index d1cd2e3c3..00a068737 100644 --- a/Src/SharpArch.Domain/PersistenceSupport/IEntityDuplicateChecker.cs +++ b/Src/SharpArch.Domain/PersistenceSupport/IEntityDuplicateChecker.cs @@ -1,8 +1,8 @@ namespace SharpArch.Domain.PersistenceSupport { using System; + using DomainModel; using JetBrains.Annotations; - using SharpArch.Domain.DomainModel; /// /// Defines the public members of a class that checks an entity for duplicates. diff --git a/Src/SharpArch.Domain/PersistenceSupport/ILinqRepository.cs b/Src/SharpArch.Domain/PersistenceSupport/ILinqRepository.cs index fb2c6cac6..be624efc1 100644 --- a/Src/SharpArch.Domain/PersistenceSupport/ILinqRepository.cs +++ b/Src/SharpArch.Domain/PersistenceSupport/ILinqRepository.cs @@ -1,13 +1,57 @@ -namespace SharpArch.Domain.PersistenceSupport +namespace SharpArch.Domain.PersistenceSupport { + using System; + using System.Linq; + using System.Threading; + using System.Threading.Tasks; + using DomainModel; using JetBrains.Annotations; + using Specifications; + /// /// Defines the public members of a LINQ supported repository. /// - /// The entity type. + /// + /// Defines a LINQ implementation of the Repository Pattern that takes in a Specification to + /// define the items that should be returned. + /// [PublicAPI] - public interface ILinqRepository : ILinqRepositoryWithTypedId - where T : class - { } + public interface ILinqRepository : IRepository + where T : class, IEntity + where TId : IEquatable + { + /// + /// Finds an item by ID. + /// + /// The ID of the entity. + /// Cancellation token. + /// The matching item. + [ItemCanBeNull] + Task FindOneAsync(TId id, CancellationToken cancellationToken = default); + + /// + /// Finds an item by a specification. + /// + /// The specification. + /// Cancellation token. + /// The matching item. + [ItemCanBeNull] + Task FindOneAsync([NotNull] ILinqSpecification specification, CancellationToken cancellationToken = default); + + /// + /// Returns representing query for the entity. + /// + /// Query. + [NotNull] + IQueryable FindAll(); + + /// + /// Returns query to filter entities by a specification. + /// + /// The specification. + /// Query. + [NotNull] + IQueryable FindAll([NotNull] ILinqSpecification specification); + } } diff --git a/Src/SharpArch.Domain/PersistenceSupport/ILinqRepositoryWithTypedId.cs b/Src/SharpArch.Domain/PersistenceSupport/ILinqRepositoryWithTypedId.cs deleted file mode 100644 index a0c830d45..000000000 --- a/Src/SharpArch.Domain/PersistenceSupport/ILinqRepositoryWithTypedId.cs +++ /dev/null @@ -1,54 +0,0 @@ -namespace SharpArch.Domain.PersistenceSupport -{ - using System.Linq; - using System.Threading; - using System.Threading.Tasks; - using JetBrains.Annotations; - using Specifications; - - - /// - /// Defines the public members of a LINQ supported repository. - /// - /// - /// Defines a LINQ implementation of the Repository Pattern that takes in a Specification to - /// define the items that should be returned. - /// - [PublicAPI] - public interface ILinqRepositoryWithTypedId : IAsyncRepositoryWithTypedId - where T : class - { - /// - /// Finds an item by ID. - /// - /// The ID of the entity. - /// Cancellation token. - /// The matching item. - [ItemCanBeNull] - Task FindOneAsync(TId id, CancellationToken cancellationToken = default); - - /// - /// Finds an item by a specification. - /// - /// The specification. - /// Cancellation token. - /// The matching item. - [ItemCanBeNull] - Task FindOneAsync([NotNull] ILinqSpecification specification, CancellationToken cancellationToken = default); - - /// - /// Returns representing query for the entity. - /// - /// Query. - [NotNull] - IQueryable FindAll(); - - /// - /// Returns query to filter entities by a specification. - /// - /// The specification. - /// Query. - [NotNull] - IQueryable FindAll([NotNull] ILinqSpecification specification); - } -} diff --git a/Src/SharpArch.Domain/PersistenceSupport/IAsyncRepositoryWithTypedId.cs b/Src/SharpArch.Domain/PersistenceSupport/IRepository.cs similarity index 74% rename from Src/SharpArch.Domain/PersistenceSupport/IAsyncRepositoryWithTypedId.cs rename to Src/SharpArch.Domain/PersistenceSupport/IRepository.cs index 3b0a19968..845efc9c4 100644 --- a/Src/SharpArch.Domain/PersistenceSupport/IAsyncRepositoryWithTypedId.cs +++ b/Src/SharpArch.Domain/PersistenceSupport/IRepository.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; + using DomainModel; using JetBrains.Annotations; @@ -11,10 +12,12 @@ /// Defines the public members of a class that implements the asynchronous repository pattern for entities /// of the specified type. /// - /// The entity type. + /// The entity type. /// The type of the entity ID. [PublicAPI] - public interface IAsyncRepositoryWithTypedId + public interface IRepository + where TEntity : class, IEntity + where TId : IEquatable { /// /// Returns the database context, which provides a handle to application wide DB @@ -32,14 +35,14 @@ public interface IAsyncRepositoryWithTypedId /// [NotNull] [ItemCanBeNull] - Task GetAsync(TId id, CancellationToken cancellationToken = default(CancellationToken)); + Task GetAsync(TId id, CancellationToken cancellationToken = default); /// /// Returns all of the items of a given type. /// [NotNull] [ItemNotNull] - Task> GetAllAsync(CancellationToken cancellationToken = default(CancellationToken)); + Task> GetAllAsync(CancellationToken cancellationToken = default); /// /// For entities that have assigned Id's, you must explicitly call Save to add a new one. @@ -48,10 +51,10 @@ public interface IAsyncRepositoryWithTypedId /// /// Saved entity instance. /// - /// is null. + /// is null. [NotNull] [ItemNotNull] - Task SaveAsync([NotNull] T entity, CancellationToken cancellationToken = default(CancellationToken)); + Task SaveAsync([NotNull] TEntity entity, CancellationToken cancellationToken = default); /// /// Saves or updates the specified entity. @@ -59,7 +62,7 @@ public interface IAsyncRepositoryWithTypedId /// /// /// For entities with automatically generated IDs, such as identity, - /// may be called when saving or updating an entity. + /// may be called when saving or updating an entity. /// /// /// Updating also allows you to commit changes to a detached object. @@ -70,10 +73,10 @@ public interface IAsyncRepositoryWithTypedId /// /// Entity instance. /// - /// is null. + /// is null. [NotNull] [ItemNotNull] - Task SaveOrUpdateAsync([NotNull] T entity, CancellationToken cancellationToken = default(CancellationToken)); + Task SaveOrUpdateAsync([NotNull] TEntity entity, CancellationToken cancellationToken = default); /// /// Disassociates the entity with the ORM so that changes made to it are not automatically @@ -83,18 +86,18 @@ public interface IAsyncRepositoryWithTypedId /// In NHibernate this removes the entity from current session cache. /// More details may be found at http://www.hibernate.org/hib_docs/nhibernate/html_single/#performance-sessioncache. /// - /// is null. - Task EvictAsync([NotNull] T entity, CancellationToken cancellationToken = default(CancellationToken)); + /// is null. + Task EvictAsync([NotNull] TEntity entity, CancellationToken cancellationToken = default); /// /// Deletes the specified entity. /// - /// is null. - Task DeleteAsync([NotNull] T entity, CancellationToken cancellationToken = default(CancellationToken)); + /// is null. + Task DeleteAsync([NotNull] TEntity entity, CancellationToken cancellationToken = default); /// /// Deletes the entity that matches the provided Id. /// - Task DeleteAsync(TId id, CancellationToken cancellationToken = default(CancellationToken)); + Task DeleteAsync(TId id, CancellationToken cancellationToken = default); } } diff --git a/Src/SharpArch.Domain/PersistenceSupport/RepositoryExtensions.cs b/Src/SharpArch.Domain/PersistenceSupport/RepositoryExtensions.cs index dcb5af5d6..c786df8e7 100644 --- a/Src/SharpArch.Domain/PersistenceSupport/RepositoryExtensions.cs +++ b/Src/SharpArch.Domain/PersistenceSupport/RepositoryExtensions.cs @@ -3,6 +3,7 @@ namespace SharpArch.Domain.PersistenceSupport using System; using System.Threading; using System.Threading.Tasks; + using DomainModel; using JetBrains.Annotations; @@ -19,9 +20,10 @@ public static class RepositoryExtensions /// or is /// . /// - public static async Task SaveAndEvictAsync( - [NotNull] this IAsyncRepositoryWithTypedId repository, [NotNull] T entity, CancellationToken cancellationToken = default) - where T : class + public static async Task SaveAndEvictAsync( + [NotNull] this IRepository repository, [NotNull] TEntity entity, CancellationToken cancellationToken = default) + where TEntity : class, IEntity + where TId : IEquatable { if (repository == null) throw new ArgumentNullException(nameof(repository)); if (entity == null) throw new ArgumentNullException(nameof(entity)); diff --git a/Src/SharpArch.Domain/SharpArch.Domain.csproj b/Src/SharpArch.Domain/SharpArch.Domain.csproj index 0b065920a..824997797 100644 --- a/Src/SharpArch.Domain/SharpArch.Domain.csproj +++ b/Src/SharpArch.Domain/SharpArch.Domain.csproj @@ -30,7 +30,6 @@ - diff --git a/Src/SharpArch.NHibernate.DependencyInjection/NHibernateRegistrationExtensions.cs b/Src/SharpArch.NHibernate.DependencyInjection/NHibernateRegistrationExtensions.cs index d690d4145..bfe8beaa4 100644 --- a/Src/SharpArch.NHibernate.DependencyInjection/NHibernateRegistrationExtensions.cs +++ b/Src/SharpArch.NHibernate.DependencyInjection/NHibernateRegistrationExtensions.cs @@ -3,6 +3,7 @@ using System; using Domain.PersistenceSupport; using global::NHibernate; + using Impl; using Infrastructure.Logging; using JetBrains.Annotations; using Microsoft.Extensions.DependencyInjection; @@ -17,9 +18,8 @@ public static class NHibernateRegistrationExtensions static readonly ILog _log = LogProvider.GetLogger("SharpArch.NHibernate.Extensions.DependencyInjection"); /// - /// Adds NHibernate classes required to support , - /// , - /// and instantiation from container. + /// Adds NHibernate classes required to support , + /// instantiation from container. /// /// and are registered as Singleton. /// diff --git a/Src/SharpArch.NHibernate/Contracts/Repositories/IAsynNHibernatecRepositoryWithTypedId.cs b/Src/SharpArch.NHibernate/Contracts/Repositories/INHibernateRepository.cs similarity index 83% rename from Src/SharpArch.NHibernate/Contracts/Repositories/IAsynNHibernatecRepositoryWithTypedId.cs rename to Src/SharpArch.NHibernate/Contracts/Repositories/INHibernateRepository.cs index 8348496d2..9b45711f6 100644 --- a/Src/SharpArch.NHibernate/Contracts/Repositories/IAsynNHibernatecRepositoryWithTypedId.cs +++ b/Src/SharpArch.NHibernate/Contracts/Repositories/INHibernateRepository.cs @@ -5,6 +5,7 @@ namespace SharpArch.NHibernate.Contracts.Repositories using System.Threading; using System.Threading.Tasks; using Domain; + using Domain.DomainModel; using Domain.PersistenceSupport; using global::NHibernate; using JetBrains.Annotations; @@ -13,11 +14,13 @@ namespace SharpArch.NHibernate.Contracts.Repositories /// /// NHibernate-specific asynchronous repository extensions. /// - /// Entity type/ + /// Entity type/ /// Entity identifier type. - /// + /// [PublicAPI] - public interface IAsyncNHibernateRepositoryWithTypedId : IAsyncRepositoryWithTypedId + public interface INHibernateRepository : IRepository + where TEntity : class, IEntity + where TId : IEquatable { /// /// Looks for zero or more instances using the properties provided. @@ -29,7 +32,7 @@ public interface IAsyncNHibernateRepositoryWithTypedId : IAsyncReposi /// Cancellation token. /// is /// No properties specified. - Task> FindAllAsync( + Task> FindAllAsync( IReadOnlyDictionary propertyValuePairs, int? maxResults = null, CancellationToken cancellationToken = default); @@ -41,8 +44,8 @@ Task> FindAllAsync( /// Names of properties to exclude from search criteria. /// Maximum number of entities to return, if return all data. /// Cancellation token. - Task> FindAllAsync( - T exampleInstance, string[] propertiesToExclude, + Task> FindAllAsync( + TEntity exampleInstance, string[] propertiesToExclude, int? maxResults = null, CancellationToken cancellationToken = default); @@ -51,7 +54,7 @@ Task> FindAllAsync( /// /// [ItemCanBeNull] - Task FindOneAsync(T exampleInstance, CancellationToken cancellationToken, params string[] propertiesToExclude); + Task FindOneAsync(TEntity exampleInstance, CancellationToken cancellationToken, params string[] propertiesToExclude); /// /// Looks for a single instance using the property/values provided. @@ -60,7 +63,7 @@ Task> FindAllAsync( /// Property name/value pairs to use as search criteria. /// Cancellation token. [ItemCanBeNull] - Task FindOneAsync( + Task FindOneAsync( IReadOnlyDictionary propertyValuePairs, CancellationToken cancellationToken = default); /// @@ -70,7 +73,7 @@ Task FindOneAsync( /// Row Lock mode. /// Cancellation token. [ItemCanBeNull] - Task GetAsync(TId id, Enums.LockMode lockMode, CancellationToken cancellationToken = default); + Task GetAsync(TId id, Enums.LockMode lockMode, CancellationToken cancellationToken = default); /// /// Return the persistent instance of the given entity class with the given identifier. @@ -78,7 +81,7 @@ Task FindOneAsync( /// Entity identifier. /// Cancellation token. [ItemNotNull] - Task LoadAsync(TId id, CancellationToken cancellationToken = default); + Task LoadAsync(TId id, CancellationToken cancellationToken = default); /// /// Return the persistent instance of the given entity class with the given identifier, obtaining the specified lock @@ -88,7 +91,7 @@ Task FindOneAsync( /// Row Lock mode. /// Cancellation token. [ItemNotNull] - Task LoadAsync(TId id, Enums.LockMode lockMode, CancellationToken cancellationToken = default); + Task LoadAsync(TId id, Enums.LockMode lockMode, CancellationToken cancellationToken = default); /// /// Copy the state of the given object onto the persistent object with the same @@ -107,7 +110,7 @@ Task FindOneAsync( /// Cancellation token. /// An updated persistent instance. [ItemNotNull] - Task MergeAsync([NotNull] T entity, CancellationToken cancellationToken = default); + Task MergeAsync([NotNull] TEntity entity, CancellationToken cancellationToken = default); /// /// For entities that have assigned Id's, you should explicitly call Update to update an existing one. @@ -119,6 +122,6 @@ Task FindOneAsync( /// Entity instance. /// is null. [ItemNotNull] - Task UpdateAsync([NotNull] T entity, CancellationToken cancellationToken = default); + Task UpdateAsync([NotNull] TEntity entity, CancellationToken cancellationToken = default); } } diff --git a/Src/SharpArch.NHibernate/EntityDuplicateChecker.cs b/Src/SharpArch.NHibernate/EntityDuplicateChecker.cs index be24d89a8..b401e007e 100644 --- a/Src/SharpArch.NHibernate/EntityDuplicateChecker.cs +++ b/Src/SharpArch.NHibernate/EntityDuplicateChecker.cs @@ -129,7 +129,7 @@ static void AppendSignaturePropertyCriteriaTo(ICriteria criteria, IEntity entity var propertyName = signatureProperty.Name; if (propertyType.GetInterfaces().Any( - x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IEntityWithTypedId<>))) { + x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IEntity<>))) { AppendEntityIdCriteriaTo(criteria, propertyName, propertyValue); } else if (typeof(ValueObject).IsAssignableFrom(propertyType)) { diff --git a/Src/SharpArch.NHibernate/FluentNHibernate/AutomappingConfiguration.cs b/Src/SharpArch.NHibernate/FluentNHibernate/AutomappingConfiguration.cs index 3536b9721..4e3a699a5 100644 --- a/Src/SharpArch.NHibernate/FluentNHibernate/AutomappingConfiguration.cs +++ b/Src/SharpArch.NHibernate/FluentNHibernate/AutomappingConfiguration.cs @@ -26,7 +26,7 @@ namespace SharpArch.NHibernate.FluentNHibernate /// /// /// - /// + /// /// [PublicAPI] public class AutomappingConfiguration : DefaultAutomappingConfiguration @@ -38,7 +38,7 @@ public override bool ShouldMap(Type type) { return !type.IsNested && type.GetInterfaces().Any(x => x.IsGenericType && - x.GetGenericTypeDefinition() == typeof(IEntityWithTypedId<>)); + x.GetGenericTypeDefinition() == typeof(IEntity<>)); } /// @@ -51,13 +51,13 @@ public override bool IsComponent(Type type) } /// - /// Marks all abstract descendants of and + /// Marks all abstract descendants of and /// as Layer Supertype. /// See http://martinfowler.com/eaaCatalog/layerSupertype.html /// public override bool AbstractClassIsLayerSupertype(Type type) { - return type == typeof(EntityWithTypedId<>) || type == typeof(Entity); + return type == typeof(Entity<>); } } } diff --git a/Src/SharpArch.NHibernate/LinqRepository.cs b/Src/SharpArch.NHibernate/LinqRepository.cs index 6efb43c71..dbfedaffe 100644 --- a/Src/SharpArch.NHibernate/LinqRepository.cs +++ b/Src/SharpArch.NHibernate/LinqRepository.cs @@ -1,26 +1,60 @@ -namespace SharpArch.NHibernate +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using JetBrains.Annotations; +using NHibernate.Linq; +using SharpArch.Domain.PersistenceSupport; +using SharpArch.Domain.Specifications; + +namespace SharpArch.NHibernate.Impl { - using Domain.PersistenceSupport; - using JetBrains.Annotations; + using System; + using Domain.DomainModel; /// /// LINQ extensions to NHibernate repository. /// - /// - /// - /// + /// Entity type. + /// The type of the identifier. + /// + /// [PublicAPI] - public class LinqRepository : LinqRepositoryWithTypedId, ILinqRepository - where T : class + public class LinqRepository : NHibernateRepository, ILinqRepository + where TEntity : class, IEntity + where TId: IEquatable { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The transaction manager. public LinqRepository(INHibernateTransactionManager transactionManager) : base(transactionManager) { } + + /// + public Task FindOneAsync(TId id, CancellationToken cancellationToken = default) + { + return Session.GetAsync(id, cancellationToken); + } + + /// + public Task FindOneAsync(ILinqSpecification specification, CancellationToken cancellationToken = default) + { + return specification.SatisfyingElementsFrom(Session.Query()).SingleOrDefaultAsync(cancellationToken); + } + + /// + public IQueryable FindAll() + { + return Session.Query(); + } + + /// + public IQueryable FindAll(ILinqSpecification specification) + { + return specification.SatisfyingElementsFrom(Session.Query()); + } } } diff --git a/Src/SharpArch.NHibernate/LinqRepositoryWithTypedId.cs b/Src/SharpArch.NHibernate/LinqRepositoryWithTypedId.cs deleted file mode 100644 index b55305b1d..000000000 --- a/Src/SharpArch.NHibernate/LinqRepositoryWithTypedId.cs +++ /dev/null @@ -1,56 +0,0 @@ -namespace SharpArch.NHibernate -{ - using System.Linq; - using System.Threading; - using System.Threading.Tasks; - using Domain.PersistenceSupport; - using Domain.Specifications; - using global::NHibernate.Linq; - using JetBrains.Annotations; - - - /// - /// LINQ extensions to NHibernate repository. - /// - /// Entity type. - /// The type of the identifier. - /// - /// - [PublicAPI] - public class LinqRepositoryWithTypedId : NHibernateRepositoryWithTypedId, ILinqRepositoryWithTypedId - where T : class - { - /// - /// Initializes a new instance of the class. - /// - /// The transaction manager. - public LinqRepositoryWithTypedId(INHibernateTransactionManager transactionManager) - : base(transactionManager) - { - } - - /// - public Task FindOneAsync(TId id, CancellationToken cancellationToken = default) - { - return Session.GetAsync(id, cancellationToken); - } - - /// - public Task FindOneAsync(ILinqSpecification specification, CancellationToken cancellationToken = default) - { - return specification.SatisfyingElementsFrom(Session.Query()).SingleOrDefaultAsync(cancellationToken); - } - - /// - public IQueryable FindAll() - { - return Session.Query(); - } - - /// - public IQueryable FindAll(ILinqSpecification specification) - { - return specification.SatisfyingElementsFrom(Session.Query()); - } - } -} diff --git a/Src/SharpArch.NHibernate/NHibernateRepository.cs b/Src/SharpArch.NHibernate/NHibernateRepository.cs index 0df6e54c6..ffefb2598 100644 --- a/Src/SharpArch.NHibernate/NHibernateRepository.cs +++ b/Src/SharpArch.NHibernate/NHibernateRepository.cs @@ -1,23 +1,27 @@ -namespace SharpArch.NHibernate +using JetBrains.Annotations; + +namespace SharpArch.NHibernate.Impl { - using JetBrains.Annotations; + using System; + using Domain.DomainModel; /// - /// Since nearly all of the domain objects you create will have a type of int Id, this - /// most frequently used base NHibernateRepository leverages this assumption. If you want - /// an entity with a type other than int, such as string, then use - /// . + /// NHibernate repository implementation. /// + /// + /// This implementation should be used in simplified, single-database model. + /// + /// Entity type/ + /// Entity identifier type. [PublicAPI] - public class NHibernateRepository : NHibernateRepositoryWithTypedId - where T : class + public class NHibernateRepository : NHibernateRepositoryBase + where TEntity : class, IEntity + where TId : IEquatable { - /// - /// Initializes a new instance of the class. - /// - /// The transaction manager. - public NHibernateRepository(INHibernateTransactionManager transactionManager) : base(transactionManager) - { } + /// + public NHibernateRepository([NotNull] INHibernateTransactionManager transactionManager) : base(transactionManager) + { + } } } diff --git a/Src/SharpArch.NHibernate/NHibernateRepositoryWithTypedId.cs b/Src/SharpArch.NHibernate/NHibernateRepositoryBase.cs similarity index 60% rename from Src/SharpArch.NHibernate/NHibernateRepositoryWithTypedId.cs rename to Src/SharpArch.NHibernate/NHibernateRepositoryBase.cs index 2a6b6f1bd..f98610eef 100644 --- a/Src/SharpArch.NHibernate/NHibernateRepositoryWithTypedId.cs +++ b/Src/SharpArch.NHibernate/NHibernateRepositoryBase.cs @@ -6,9 +6,11 @@ namespace SharpArch.NHibernate using System.Threading.Tasks; using Contracts.Repositories; using Domain; + using Domain.DomainModel; using Domain.PersistenceSupport; using global::NHibernate; using global::NHibernate.Criterion; + using Impl; using JetBrains.Annotations; @@ -19,9 +21,16 @@ namespace SharpArch.NHibernate /// /// + /// + /// Keep constructor protected to enable support of single-database () + /// and multiple-database + /// + /// Entity type/ + /// Entity identifier type. [PublicAPI] - public class NHibernateRepositoryWithTypedId : IAsyncNHibernateRepositoryWithTypedId - where T : class + public class NHibernateRepositoryBase : INHibernateRepository + where TEntity : class, IEntity + where TId : IEquatable { /// /// Gets NHibernate session. @@ -36,47 +45,47 @@ public class NHibernateRepositoryWithTypedId : IAsyncNHibernateRepositor protected INHibernateTransactionManager TransactionManager { get; } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The transaction manager. /// - public NHibernateRepositoryWithTypedId( + protected NHibernateRepositoryBase( [NotNull] INHibernateTransactionManager transactionManager) { TransactionManager = transactionManager ?? throw new ArgumentNullException(nameof(transactionManager)); } /// - public Task GetAsync(TId id, CancellationToken cancellationToken = default) - => Session.GetAsync(id, cancellationToken); + public Task GetAsync(TId id, CancellationToken cancellationToken = default) + => Session.GetAsync(id, cancellationToken); /// - public Task> GetAllAsync(CancellationToken cancellationToken = default) + public Task> GetAllAsync(CancellationToken cancellationToken = default) { - ICriteria criteria = Session.CreateCriteria(typeof(T)); - return criteria.ListAsync(cancellationToken); + ICriteria criteria = Session.CreateCriteria(typeof(TEntity)); + return criteria.ListAsync(cancellationToken); } /// - public async Task SaveAsync(T entity, CancellationToken cancellationToken = default) + public async Task SaveAsync(TEntity entity, CancellationToken cancellationToken = default) { await Session.SaveAsync(entity, cancellationToken).ConfigureAwait(false); return entity; } /// - public async Task SaveOrUpdateAsync(T entity, CancellationToken cancellationToken = default) + public async Task SaveOrUpdateAsync(TEntity entity, CancellationToken cancellationToken = default) { await Session.SaveOrUpdateAsync(entity, cancellationToken).ConfigureAwait(false); return entity; } /// - public Task EvictAsync(T entity, CancellationToken cancellationToken = default) + public Task EvictAsync(TEntity entity, CancellationToken cancellationToken = default) => Session.EvictAsync(entity, cancellationToken); /// - public Task DeleteAsync(T entity, CancellationToken cancellationToken = default) + public Task DeleteAsync(TEntity entity, CancellationToken cancellationToken = default) => Session.DeleteAsync(entity, cancellationToken); /// @@ -86,10 +95,10 @@ public async Task DeleteAsync(TId id, CancellationToken cancellationToken = defa if (entity != null) await DeleteAsync(entity, cancellationToken).ConfigureAwait(false); } - ITransactionManager IAsyncRepositoryWithTypedId.TransactionManager => TransactionManager; + ITransactionManager IRepository.TransactionManager => TransactionManager; /// - public virtual Task> FindAllAsync( + public virtual Task> FindAllAsync( IReadOnlyDictionary propertyValuePairs, int? maxResults = null, CancellationToken cancellationToken = default) @@ -99,7 +108,7 @@ public virtual Task> FindAllAsync( throw new ArgumentException("No properties specified. Please specify at least one property/value pair.", nameof(propertyValuePairs)); - ICriteria criteria = Session.CreateCriteria(typeof(T)); + ICriteria criteria = Session.CreateCriteria(typeof(TEntity)); foreach (string key in propertyValuePairs.Keys) { criteria.Add(propertyValuePairs[key] != null @@ -108,14 +117,14 @@ public virtual Task> FindAllAsync( } if (maxResults.HasValue) criteria.SetMaxResults(maxResults.Value); - return criteria.ListAsync(cancellationToken); + return criteria.ListAsync(cancellationToken); } /// - public Task> FindAllAsync( - T exampleInstance, string[] propertiesToExclude, int? maxResults = null, CancellationToken cancellationToken = default) + public Task> FindAllAsync( + TEntity exampleInstance, string[] propertiesToExclude, int? maxResults = null, CancellationToken cancellationToken = default) { - ICriteria criteria = Session.CreateCriteria(typeof(T)); + ICriteria criteria = Session.CreateCriteria(typeof(TEntity)); Example example = Example.Create(exampleInstance); foreach (string propertyToExclude in propertiesToExclude) example.ExcludeProperty(propertyToExclude); @@ -124,20 +133,20 @@ public Task> FindAllAsync( if (maxResults.HasValue) criteria.SetMaxResults(maxResults.Value); - return criteria.ListAsync(cancellationToken); + return criteria.ListAsync(cancellationToken); } /// - public virtual async Task FindOneAsync(T exampleInstance, CancellationToken ct, params string[] propertiesToExclude) + public virtual async Task FindOneAsync(TEntity exampleInstance, CancellationToken ct, params string[] propertiesToExclude) { - IList foundList = await FindAllAsync(exampleInstance, propertiesToExclude, 2, ct).ConfigureAwait(false); + IList foundList = await FindAllAsync(exampleInstance, propertiesToExclude, 2, ct).ConfigureAwait(false); if (foundList.Count > 1) throw new NonUniqueResultException(foundList.Count); return foundList.Count == 1 ? foundList[0] : default; } /// - public async Task FindOneAsync( + public async Task FindOneAsync( IReadOnlyDictionary propertyValuePairs, CancellationToken cancellationToken = default) { @@ -148,23 +157,23 @@ public async Task FindOneAsync( } /// - public virtual Task GetAsync(TId id, Enums.LockMode lockMode, CancellationToken ct) - => Session.GetAsync(id, ConvertFrom(lockMode), ct); + public virtual Task GetAsync(TId id, Enums.LockMode lockMode, CancellationToken ct) + => Session.GetAsync(id, ConvertFrom(lockMode), ct); /// - public virtual Task LoadAsync(TId id, CancellationToken ct) - => Session.LoadAsync(id, ct); + public virtual Task LoadAsync(TId id, CancellationToken ct) + => Session.LoadAsync(id, ct); /// - public virtual Task LoadAsync(TId id, Enums.LockMode lockMode, CancellationToken ct) - => Session.LoadAsync(id, ConvertFrom(lockMode), ct); + public virtual Task LoadAsync(TId id, Enums.LockMode lockMode, CancellationToken ct) + => Session.LoadAsync(id, ConvertFrom(lockMode), ct); /// - public Task MergeAsync(T entity, CancellationToken cancellationToken = default) + public Task MergeAsync(TEntity entity, CancellationToken cancellationToken = default) => Session.MergeAsync(entity, cancellationToken); /// - public virtual async Task UpdateAsync(T entity, CancellationToken ct) + public virtual async Task UpdateAsync(TEntity entity, CancellationToken ct) { await Session.UpdateAsync(entity, ct).ConfigureAwait(false); return entity; @@ -176,26 +185,17 @@ public virtual async Task UpdateAsync(T entity, CancellationToken ct) /// NHibernate assembly. /// static LockMode ConvertFrom(Enums.LockMode lockMode) - { - switch (lockMode) + => lockMode switch { - case Enums.LockMode.None: - return LockMode.None; - case Enums.LockMode.Read: - return LockMode.Read; - case Enums.LockMode.Upgrade: - return LockMode.Upgrade; - case Enums.LockMode.UpgradeNoWait: - return LockMode.UpgradeNoWait; - case Enums.LockMode.Write: - return LockMode.Write; - default: - throw new ArgumentOutOfRangeException(nameof(lockMode), lockMode, - "The provided lock mode , '" + lockMode + - "', could not be translated into an NHibernate.LockMode. " + - "This is probably because NHibernate was updated and now has different lock modes which are out of synch " + - "with the lock modes maintained in the domain layer."); - } - } + Enums.LockMode.None => LockMode.None, + Enums.LockMode.Read => LockMode.Read, + Enums.LockMode.Upgrade => LockMode.Upgrade, + Enums.LockMode.UpgradeNoWait => LockMode.UpgradeNoWait, + Enums.LockMode.Write => LockMode.Write, + _ => throw new ArgumentOutOfRangeException(nameof(lockMode), lockMode, + "The provided lock mode , '" + lockMode + "', could not be translated into an NHibernate.LockMode. " + + "This is probably because NHibernate was updated and now has different lock modes which are out of synch " + + "with the lock modes maintained in the domain layer.") + }; } } diff --git a/Src/SharpArch.NHibernate/TransactionManager.cs b/Src/SharpArch.NHibernate/TransactionManager.cs index dcd9098c5..a807d8a0a 100644 --- a/Src/SharpArch.NHibernate/TransactionManager.cs +++ b/Src/SharpArch.NHibernate/TransactionManager.cs @@ -1,4 +1,4 @@ -namespace SharpArch.NHibernate +namespace SharpArch.NHibernate.Impl { using System; using System.Data; diff --git a/Src/SharpArch.RavenDb/Contracts/Repositories/IRavenDbRepository.cs b/Src/SharpArch.RavenDb/Contracts/Repositories/IRavenDbRepository.cs index 2878b8abd..56da621bb 100644 --- a/Src/SharpArch.RavenDb/Contracts/Repositories/IRavenDbRepository.cs +++ b/Src/SharpArch.RavenDb/Contracts/Repositories/IRavenDbRepository.cs @@ -1,15 +1,64 @@ namespace SharpArch.RavenDb.Contracts.Repositories { + using System; + using System.Collections.Generic; + using System.Linq.Expressions; + using System.Threading; + using System.Threading.Tasks; + using Domain.DomainModel; + using Domain.PersistenceSupport; using JetBrains.Annotations; + using Raven.Client.Documents.Session; + /// - /// RavenDB repository for documents with primary key of type . + /// RavenDB-specific repository implementation. /// - /// The document type. - /// + /// + /// The type of the identifier t. + /// [PublicAPI] - public interface IRavenDbRepository : IRavenDbRepositoryWithTypedId - where T : class + public interface IRavenDbRepository : IRepository + where TEntity : class, IEntity + where TIdT : IEquatable { + /// + /// RavenDB Document Session. + /// + IAsyncDocumentSession Session { get; } + + /// + /// Finds all documents satisfying given criteria. + /// + /// The criteria. + /// Cancellation token. + /// Documents + Task> FindAllAsync(Expression> where, CancellationToken cancellationToken = default); + + /// + /// Finds single document satisfying given criteria. + /// + /// The criteria. + /// Cancellation token. + /// The document + /// If more than one document found. + Task FindOneAsync(Expression> where, CancellationToken cancellationToken = default); + + /// + /// Finds the first document satisfying given criteria. + /// + /// The Criteria. + /// Cancellation token. + /// The document. + /// If no documents found. + Task FirstAsync(Expression> where, CancellationToken cancellationToken = default); + + /// + /// Loads all documents with given IDs. + /// + /// Document IDs. + /// Cancellation token. + /// List of documents. + Task> GetAllAsync(IEnumerable ids, CancellationToken cancellationToken = default); } } diff --git a/Src/SharpArch.RavenDb/Contracts/Repositories/IRavenDbRepositoryWithTypedId.cs b/Src/SharpArch.RavenDb/Contracts/Repositories/IRavenDbRepositoryWithTypedId.cs deleted file mode 100644 index 5abe7b3fd..000000000 --- a/Src/SharpArch.RavenDb/Contracts/Repositories/IRavenDbRepositoryWithTypedId.cs +++ /dev/null @@ -1,62 +0,0 @@ -namespace SharpArch.RavenDb.Contracts.Repositories -{ - using System; - using System.Collections.Generic; - using System.Linq.Expressions; - using System.Threading; - using System.Threading.Tasks; - using Domain.PersistenceSupport; - using JetBrains.Annotations; - using Raven.Client.Documents.Session; - - - /// - /// RavenDB-specific repository implementation. - /// - /// - /// The type of the identifier t. - /// - [PublicAPI] - public interface IRavenDbRepositoryWithTypedId : IAsyncRepositoryWithTypedId - where T : class - { - /// - /// RavenDB Document Session. - /// - IAsyncDocumentSession Session { get; } - - /// - /// Finds all documents satisfying given criteria. - /// - /// The criteria. - /// Cancellation token. - /// Documents - Task> FindAllAsync(Expression> where, CancellationToken cancellationToken = default); - - /// - /// Finds single document satisfying given criteria. - /// - /// The criteria. - /// Cancellation token. - /// The document - /// If more than one document found. - Task FindOneAsync(Expression> where, CancellationToken cancellationToken = default); - - /// - /// Finds the first document satisfying given criteria. - /// - /// The Criteria. - /// Cancellation token. - /// The document. - /// If no documents found. - Task FirstAsync(Expression> where, CancellationToken cancellationToken = default); - - /// - /// Loads all documents with given IDs. - /// - /// Document IDs. - /// Cancellation token. - /// List of documents. - Task> GetAllAsync(IEnumerable ids, CancellationToken cancellationToken = default); - } -} diff --git a/Src/SharpArch.RavenDb/RavenDbRepository.cs b/Src/SharpArch.RavenDb/RavenDbRepository.cs index 0c2643a79..66737fd35 100644 --- a/Src/SharpArch.RavenDb/RavenDbRepository.cs +++ b/Src/SharpArch.RavenDb/RavenDbRepository.cs @@ -1,32 +1,171 @@ namespace SharpArch.RavenDb { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Linq.Expressions; + using System.Threading; + using System.Threading.Tasks; using Contracts.Repositories; + using Domain.DomainModel; using Domain.PersistenceSupport; + using Domain.Specifications; using JetBrains.Annotations; + using Raven.Client.Documents; + using Raven.Client.Documents.Commands.Batches; using Raven.Client.Documents.Session; /// - /// RavenDB repository. - /// This repository supports entities with primary key of type . + /// RavenDB repository base class. + /// Implements repository for given entity type. /// - /// Entity type. - /// - /// - /// + /// Entity type + /// Primary Key type. + /// + /// [PublicAPI] - public class RavenDbRepository : RavenDbRepositoryWithTypedId, - IRavenDbRepository, - ILinqRepository - where T : class + public class RavenDbRepository : IRavenDbRepository, + ILinqRepository + where TEntity : class, IEntity + where TId : IEquatable { /// - /// Initializes a new instance of the class. + /// RavenDB Document Session. + /// + public IAsyncDocumentSession Session { get; } + + /// + /// Initializes a new instance of the class. /// /// The session. - public RavenDbRepository(IAsyncDocumentSession session) - : base(session) + public RavenDbRepository([NotNull] IAsyncDocumentSession session) + { + Session = session ?? throw new ArgumentNullException(nameof(session)); + TransactionManager = new TransactionManager(session); + } + + /// + public Task FindOneAsync(TId id, CancellationToken cancellationToken = default) + => GetAsync(id, cancellationToken); + + /// + public Task FindOneAsync(ILinqSpecification specification, CancellationToken cancellationToken = default) + { + if (specification == null) throw new ArgumentNullException(nameof(specification)); + return specification.SatisfyingElementsFrom(Session.Query()) + .SingleOrDefaultAsync(cancellationToken); + } + + /// + /// Finds all items within the repository. + /// + /// + /// All items in the repository. + /// + public IQueryable FindAll() + => Session.Query(); + + /// + /// Finds all items by a specification. + /// + /// The specification. + /// + /// All matching items. + /// + public IQueryable FindAll(ILinqSpecification specification) + => specification.SatisfyingElementsFrom(FindAll()); + + /// + public async Task> FindAllAsync(Expression> where, CancellationToken cancellationToken = default) + { + var result = await Session.Query().Where(where).ToArrayAsync(cancellationToken).ConfigureAwait(false); + return result; + } + + /// + public async Task FindOneAsync(Expression> where, CancellationToken cancellationToken = default) + { + var result = await Session.Query().Where(where).SingleOrDefaultAsync(cancellationToken).ConfigureAwait(false); + return result + ?? throw new InvalidOperationException("The query returned more than one result. Please refine your query."); + } + + /// + public async Task FirstAsync(Expression> where, CancellationToken cancellationToken = default) + { + var result = await Session.Query().Where(where).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false); + return result + ?? throw new InvalidOperationException("The query returned no results. Please refine your query."); + } + + /// + public async Task> GetAllAsync(IEnumerable ids, CancellationToken cancellationToken = default) + { + var all = await Session.LoadAsync(ids.Select(p => p.ToString()), cancellationToken).ConfigureAwait(false); + return all.Select(kvp => kvp.Value).ToList(); + } + + /// + /// Returns the database context, which provides a handle to application wide DB + /// activities such as committing any pending changes, beginning a transaction, + /// rolling back a transaction, etc. + /// + public virtual ITransactionManager TransactionManager { get; } + + /// + public Task GetAsync(TId id, CancellationToken cancellationToken = default) + => Session.LoadAsync(id.ToString(), cancellationToken); + + /// + public async Task> GetAllAsync(CancellationToken cancellationToken = default) + { + var result = await Session.Query().ToListAsync(cancellationToken).ConfigureAwait(false); + return result; + } + + /// + public async Task SaveAsync(TEntity entity, CancellationToken cancellationToken = default) { + if (entity == null) throw new ArgumentNullException(nameof(entity)); + await Session.StoreAsync(entity, cancellationToken).ConfigureAwait(false); + return entity; } + + /// + public Task SaveOrUpdateAsync(TEntity entity, CancellationToken cancellationToken = default) + => SaveAsync(entity, cancellationToken); + + /// + public Task EvictAsync(TEntity entity, CancellationToken cancellationToken = default) + { + Session.Advanced.Evict(entity); + return Task.CompletedTask; + } + + /// + public Task DeleteAsync(TEntity entity, CancellationToken cancellationToken = default) + { + cancellationToken.ThrowIfCancellationRequested(); + Session.Delete(entity); + return Task.CompletedTask; + } + + /// + public async Task DeleteAsync(TId id, CancellationToken cancellationToken = default) + { + if (id is ValueType) + { + var entity = await GetAsync(id, cancellationToken).ConfigureAwait(false); + await DeleteAsync(entity, cancellationToken).ConfigureAwait(false); + } + else + { + Session.Advanced.Defer(new DeleteCommandData(id.ToString(), null)); + } + } + + /// + IAsyncDocumentSession IRavenDbRepository.Session { get; } } } diff --git a/Src/SharpArch.RavenDb/RavenDbRepositoryWithTypedId.cs b/Src/SharpArch.RavenDb/RavenDbRepositoryWithTypedId.cs deleted file mode 100644 index e8c5136c6..000000000 --- a/Src/SharpArch.RavenDb/RavenDbRepositoryWithTypedId.cs +++ /dev/null @@ -1,169 +0,0 @@ -namespace SharpArch.RavenDb -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Linq.Expressions; - using System.Threading; - using System.Threading.Tasks; - using Contracts.Repositories; - using Domain.PersistenceSupport; - using Domain.Specifications; - using JetBrains.Annotations; - using Raven.Client.Documents; - using Raven.Client.Documents.Commands.Batches; - using Raven.Client.Documents.Session; - - - /// - /// RavenDB repository base class. - /// Implements repository for given entity type. - /// - /// Entity type - /// Primary Key type. - /// - /// - [PublicAPI] - public class RavenDbRepositoryWithTypedId : IRavenDbRepositoryWithTypedId, - ILinqRepositoryWithTypedId - where T : class - { - /// - /// RavenDB Document Session. - /// - public IAsyncDocumentSession Session { get; } - - /// - /// Initializes a new instance of the class. - /// - /// The session. - public RavenDbRepositoryWithTypedId([NotNull] IAsyncDocumentSession session) - { - Session = session ?? throw new ArgumentNullException(nameof(session)); - TransactionManager = new TransactionManager(session); - } - - /// - public Task FindOneAsync(TIdT id, CancellationToken cancellationToken = default) - => GetAsync(id, cancellationToken); - - /// - public Task FindOneAsync(ILinqSpecification specification, CancellationToken cancellationToken = default) - { - if (specification == null) throw new ArgumentNullException(nameof(specification)); - return specification.SatisfyingElementsFrom(Session.Query()) - .SingleOrDefaultAsync(cancellationToken); - } - - /// - /// Finds all items within the repository. - /// - /// - /// All items in the repository. - /// - public IQueryable FindAll() - => Session.Query(); - - /// - /// Finds all items by a specification. - /// - /// The specification. - /// - /// All matching items. - /// - public IQueryable FindAll(ILinqSpecification specification) - => specification.SatisfyingElementsFrom(FindAll()); - - /// - public async Task> FindAllAsync(Expression> where, CancellationToken cancellationToken = default) - { - var result = await Session.Query().Where(where).ToArrayAsync(cancellationToken).ConfigureAwait(false); - return result; - } - - /// - public async Task FindOneAsync(Expression> where, CancellationToken cancellationToken = default) - { - var result = await Session.Query().Where(where).SingleOrDefaultAsync(cancellationToken).ConfigureAwait(false); - return result - ?? throw new InvalidOperationException("The query returned more than one result. Please refine your query."); - } - - /// - public async Task FirstAsync(Expression> where, CancellationToken cancellationToken = default) - { - var result = await Session.Query().Where(where).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false); - return result - ?? throw new InvalidOperationException("The query returned no results. Please refine your query."); - } - - /// - public async Task> GetAllAsync(IEnumerable ids, CancellationToken cancellationToken = default) - { - var all = await Session.LoadAsync(ids.Select(p => p.ToString()), cancellationToken).ConfigureAwait(false); - return all.Select(kvp => kvp.Value).ToList(); - } - - /// - /// Returns the database context, which provides a handle to application wide DB - /// activities such as committing any pending changes, beginning a transaction, - /// rolling back a transaction, etc. - /// - public virtual ITransactionManager TransactionManager { get; } - - /// - public Task GetAsync(TIdT id, CancellationToken cancellationToken = default) - => Session.LoadAsync(id.ToString(), cancellationToken); - - /// - public async Task> GetAllAsync(CancellationToken cancellationToken = default) - { - var result = await Session.Query().ToListAsync(cancellationToken).ConfigureAwait(false); - return result; - } - - /// - public async Task SaveAsync(T entity, CancellationToken cancellationToken = default) - { - if (entity == null) throw new ArgumentNullException(nameof(entity)); - await Session.StoreAsync(entity, cancellationToken).ConfigureAwait(false); - return entity; - } - - /// - public Task SaveOrUpdateAsync(T entity, CancellationToken cancellationToken = default) - => SaveAsync(entity, cancellationToken); - - /// - public Task EvictAsync(T entity, CancellationToken cancellationToken = default) - { - Session.Advanced.Evict(entity); - return Task.CompletedTask; - } - - /// - public Task DeleteAsync(T entity, CancellationToken cancellationToken = default) - { - cancellationToken.ThrowIfCancellationRequested(); - Session.Delete(entity); - return Task.CompletedTask; - } - - /// - public async Task DeleteAsync(TIdT id, CancellationToken cancellationToken = default) - { - if (id is ValueType) - { - var entity = await GetAsync(id, cancellationToken).ConfigureAwait(false); - await DeleteAsync(entity, cancellationToken).ConfigureAwait(false); - } - else - { - Session.Advanced.Defer(new DeleteCommandData(id.ToString(), null)); - } - } - - /// - IAsyncDocumentSession IRavenDbRepositoryWithTypedId.Session { get; } - } -} diff --git a/Src/SharpArch.Testing.NUnit/NHibernate/RepositoryTestsBase.cs b/Src/SharpArch.Testing.NUnit/NHibernate/RepositoryTestsBase.cs index 83e60540f..a00ce6e9b 100644 --- a/Src/SharpArch.Testing.NUnit/NHibernate/RepositoryTestsBase.cs +++ b/Src/SharpArch.Testing.NUnit/NHibernate/RepositoryTestsBase.cs @@ -5,6 +5,7 @@ using global::NUnit.Framework; using JetBrains.Annotations; using SharpArch.NHibernate; + using SharpArch.NHibernate.Impl; using Testing.NHibernate; diff --git a/Src/SharpArch.Testing.Xunit.NHibernate/TransientDatabaseTests.cs b/Src/SharpArch.Testing.Xunit.NHibernate/TransientDatabaseTests.cs index 6dbd94860..de96d9358 100644 --- a/Src/SharpArch.Testing.Xunit.NHibernate/TransientDatabaseTests.cs +++ b/Src/SharpArch.Testing.Xunit.NHibernate/TransientDatabaseTests.cs @@ -5,6 +5,7 @@ using global::Xunit; using JetBrains.Annotations; using SharpArch.NHibernate; + using SharpArch.NHibernate.Impl; using SharpArch.Testing.NHibernate; diff --git a/Src/SharpArch.Testing/Helpers/EntityIdSetter.cs b/Src/SharpArch.Testing/Helpers/EntityIdSetter.cs index 8e3b196af..7ac734a8c 100644 --- a/Src/SharpArch.Testing/Helpers/EntityIdSetter.cs +++ b/Src/SharpArch.Testing/Helpers/EntityIdSetter.cs @@ -6,7 +6,7 @@ using Domain.DomainModel; /// - /// For better data integrity, it is imperative that the + /// For better data integrity, it is imperative that the /// property is read-only and set only by the ORM. With that said, some unit tests need /// Id set to a particular value; therefore, this utility enables that ability. This class should /// never be used outside of the testing project; instead, implement to @@ -16,11 +16,11 @@ public static class EntityIdSetter { /// - /// Uses reflection to set the Id of a . + /// Uses reflection to set the Id of a . /// /// is . /// Property with name 'Id' could not be found. - public static void SetIdOf([NotNull] IEntityWithTypedId entity, TId id) + public static void SetIdOf([NotNull] IEntity entity, TId id) where TId : IEquatable { if (entity == null) throw new ArgumentNullException(nameof(entity)); @@ -34,9 +34,9 @@ public static void SetIdOf([NotNull] IEntityWithTypedId entity, TId id } /// - /// Uses reflection to set the Id of a . + /// Uses reflection to set the Id of a . /// - public static IEntityWithTypedId SetIdTo(this IEntityWithTypedId entity, TId id) + public static IEntity SetIdTo(this IEntity entity, TId id) where TId : IEquatable { SetIdOf(entity, id); diff --git a/Src/Tests/SharpArch.Tests.NHibernate/Mappings/AutoPersistenceModelGenerator.cs b/Src/Tests/SharpArch.Tests.NHibernate/Mappings/AutoPersistenceModelGenerator.cs index d2d5d21d3..df1b13c56 100644 --- a/Src/Tests/SharpArch.Tests.NHibernate/Mappings/AutoPersistenceModelGenerator.cs +++ b/Src/Tests/SharpArch.Tests.NHibernate/Mappings/AutoPersistenceModelGenerator.cs @@ -25,8 +25,7 @@ public class TestsPersistenceModelGenerator : IAutoPersistenceModelGenerator public AutoPersistenceModel Generate() { var mappings = AutoMap.AssemblyOf(new AutomappingConfiguration()); - mappings.IgnoreBase(); - mappings.IgnoreBase(typeof(EntityWithTypedId<>)); + mappings.IgnoreBase(typeof(Entity<>)); mappings.Conventions.Setup(GetConventions()); mappings.UseOverridesFromAssemblyOf(); diff --git a/Src/Tests/SharpArch.Tests.NHibernate/RepositoryTests.cs b/Src/Tests/SharpArch.Tests.NHibernate/RepositoryTests.cs index 4a2024f22..29b8a446c 100644 --- a/Src/Tests/SharpArch.Tests.NHibernate/RepositoryTests.cs +++ b/Src/Tests/SharpArch.Tests.NHibernate/RepositoryTests.cs @@ -6,8 +6,10 @@ namespace Tests.SharpArch.NHibernate { using FluentAssertions; using global::NHibernate; + using global::SharpArch.Domain.DomainModel; using global::SharpArch.Domain.PersistenceSupport; using global::SharpArch.NHibernate; + using global::SharpArch.NHibernate.Impl; using Moq; using NUnit.Framework; @@ -22,14 +24,14 @@ public void CanCastConcreteLinqRepositoryToInterfaceILinqRepository() var session = new Mock(); var transactionManager = new Mock(); transactionManager.SetupGet(t => t.Session).Returns(session.Object); - var concreteRepository = new LinqRepository(transactionManager.Object); + var concreteRepository = new LinqRepository(transactionManager.Object); - concreteRepository.Should().BeAssignableTo>(); + concreteRepository.Should().BeAssignableTo>(); } } - public class MyEntity + public class MyEntity: Entity { string Name { get; set; } } diff --git a/Src/Tests/SharpArch.XunitTests.NHibernate/Mappings/TestsPersistenceModelGenerator.cs b/Src/Tests/SharpArch.XunitTests.NHibernate/Mappings/TestsPersistenceModelGenerator.cs index 9291dfdc6..02baa8313 100644 --- a/Src/Tests/SharpArch.XunitTests.NHibernate/Mappings/TestsPersistenceModelGenerator.cs +++ b/Src/Tests/SharpArch.XunitTests.NHibernate/Mappings/TestsPersistenceModelGenerator.cs @@ -21,8 +21,7 @@ public class TestsPersistenceModelGenerator : IAutoPersistenceModelGenerator public AutoPersistenceModel Generate() { var mappings = AutoMap.AssemblyOf(new AutomappingConfiguration()); - mappings.IgnoreBase(); - mappings.IgnoreBase(typeof(EntityWithTypedId<>)); + mappings.IgnoreBase(typeof(Entity<>)); mappings.Conventions.Setup(GetConventions()); mappings.UseOverridesFromAssemblyOf(); diff --git a/Src/Tests/SharpArch.XunitTests.NHibernate/NHibernateRepositoryTests.cs b/Src/Tests/SharpArch.XunitTests.NHibernate/NHibernateRepositoryTests.cs index 6a272c671..087da4db4 100644 --- a/Src/Tests/SharpArch.XunitTests.NHibernate/NHibernateRepositoryTests.cs +++ b/Src/Tests/SharpArch.XunitTests.NHibernate/NHibernateRepositoryTests.cs @@ -3,19 +3,19 @@ using System.Threading.Tasks; using Domain; using FluentAssertions; - using global::SharpArch.NHibernate; + using global::SharpArch.NHibernate.Impl; using global::SharpArch.Testing.Xunit.NHibernate; using Xunit; public class NHibernateRepositoryTests : TransientDatabaseTests { - readonly NHibernateRepository _repo; + readonly NHibernateRepository _repo; /// public NHibernateRepositoryTests(NHibernateTestsSetup setup): base(setup) { - _repo = new NHibernateRepository(TransactionManager); + _repo = new NHibernateRepository(TransactionManager); } /// diff --git a/Src/Tests/SharpArch.XunitTests.NHibernate/NHibernateTestsSetup.cs b/Src/Tests/SharpArch.XunitTests.NHibernate/NHibernateTestsSetup.cs index 94514663c..6bcee281a 100644 --- a/Src/Tests/SharpArch.XunitTests.NHibernate/NHibernateTestsSetup.cs +++ b/Src/Tests/SharpArch.XunitTests.NHibernate/NHibernateTestsSetup.cs @@ -13,7 +13,7 @@ public class NHibernateTestsSetup : TestDatabaseSetup { public NHibernateTestsSetup() - : base(Assembly.GetExecutingAssembly().CodeBase, + : base(Assembly.GetExecutingAssembly().Location, new[] { typeof(ObjectWithGuidId).Assembly, diff --git a/Src/Tests/SharpArch.XunitTests.NHibernate/RepositoryTests.cs b/Src/Tests/SharpArch.XunitTests.NHibernate/RepositoryTests.cs index d61c443b8..721606be6 100644 --- a/Src/Tests/SharpArch.XunitTests.NHibernate/RepositoryTests.cs +++ b/Src/Tests/SharpArch.XunitTests.NHibernate/RepositoryTests.cs @@ -2,8 +2,10 @@ namespace Tests.SharpArch.NHibernate { using FluentAssertions; using global::NHibernate; + using global::SharpArch.Domain.DomainModel; using global::SharpArch.Domain.PersistenceSupport; using global::SharpArch.NHibernate; + using global::SharpArch.NHibernate.Impl; using Moq; using Xunit; @@ -16,14 +18,14 @@ public void CanCastConcreteLinqRepositoryToInterfaceILinqRepository() var session = new Mock(); var transactionManager = new Mock(); transactionManager.SetupGet(t => t.Session).Returns(session.Object); - var concreteRepository = new LinqRepository(transactionManager.Object); + var concreteRepository = new LinqRepository(transactionManager.Object); - concreteRepository.Should().BeAssignableTo>(); + concreteRepository.Should().BeAssignableTo>(); } } - public class MyEntity + public class MyEntity: Entity { string Name { get; set; } } diff --git a/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/DataAnnotationsValidator/HasUniqueEntitySignatureValidatorTests.cs b/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/DataAnnotationsValidator/HasUniqueEntitySignatureValidatorTests.cs index 0c389a0e9..d03310eab 100644 --- a/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/DataAnnotationsValidator/HasUniqueEntitySignatureValidatorTests.cs +++ b/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/DataAnnotationsValidator/HasUniqueEntitySignatureValidatorTests.cs @@ -30,7 +30,7 @@ ValidationContext ValidationContextFor(object instance) [HasUniqueDomainSignature] - class Contractor : Entity + class Contractor : Entity { [DomainSignature] public string Name { get; set; } @@ -59,7 +59,7 @@ public bool DoesDuplicateExistWithTypedIdOf(IEntity entity) [HasUniqueDomainSignature] - class ObjectWithGuidId : EntityWithTypedId + class ObjectWithGuidId : Entity { [DomainSignature] public string Name { get; set; } @@ -67,7 +67,7 @@ class ObjectWithGuidId : EntityWithTypedId [HasUniqueDomainSignature] - class ObjectWithStringIdAndValidatorForIntId : EntityWithTypedId + class ObjectWithStringIdAndValidatorForIntId : Entity { [DomainSignature] public string Name { get; set; } @@ -75,7 +75,7 @@ class ObjectWithStringIdAndValidatorForIntId : EntityWithTypedId [HasUniqueDomainSignature] - class User : EntityWithTypedId + class User : Entity { [DomainSignature] public string Ssn { get; set; } diff --git a/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/DomainModel/BaseObjectEqualityComparerTests.cs b/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/DomainModel/BaseObjectEqualityComparerTests.cs index 40d0cc3e8..838bef75c 100644 --- a/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/DomainModel/BaseObjectEqualityComparerTests.cs +++ b/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/DomainModel/BaseObjectEqualityComparerTests.cs @@ -22,14 +22,14 @@ protected override PropertyInfo[] GetTypeSpecificSignatureProperties() } - class ConcreteEntityWithDomainSignatureProperties : Entity + class ConcreteEntityWithDomainSignatureProperties : Entity { [DomainSignature] public string Name { get; set; } } - class ConcreteEntityWithNoDomainSignatureProperties : Entity + class ConcreteEntityWithNoDomainSignatureProperties : Entity { public string Name { get; set; } } @@ -92,7 +92,7 @@ public void CanCompareBaseObjects() [Fact] public void CanCompareEntitiesWithDomainSignatureProperties() { - var comparer = new BaseObjectEqualityComparer(); + var comparer = new BaseObjectEqualityComparer>(); var obj1 = new ConcreteEntityWithDomainSignatureProperties {Name = "Whatever"}; var obj2 = new ConcreteEntityWithDomainSignatureProperties {Name = "Whatever"}; diff --git a/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/DomainModel/EntityTests.cs b/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/DomainModel/EntityTests.cs index af456c1d4..420da7933 100644 --- a/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/DomainModel/EntityTests.cs +++ b/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/DomainModel/EntityTests.cs @@ -64,7 +64,7 @@ public EntityTests() } - public abstract class MockEntityObjectBase : EntityWithTypedId + public abstract class MockEntityObjectBase : Entity where T : IEquatable { public string Email { get; set; } @@ -77,7 +77,7 @@ public abstract class MockEntityObjectBase : EntityWithTypedId } - public class ObjectWithOneDomainSignatureProperty : Entity + public class ObjectWithOneDomainSignatureProperty : Entity { [DomainSignature] public int Age { get; set; } @@ -86,7 +86,7 @@ public class ObjectWithOneDomainSignatureProperty : Entity } - class AddressBeingDomainSignatureComparable : Entity + class AddressBeingDomainSignatureComparable : Entity { [DomainSignature] public string Address1 { get; set; } @@ -130,17 +130,17 @@ public void SetAssignedIdTo(string assignedId) } - class Entity1 : Entity + class Entity1 : Entity { } - class Entity2 : Entity + class Entity2 : Entity { } - class ObjectWithAllDomainSignatureProperty : Entity + class ObjectWithAllDomainSignatureProperty : Entity { [DomainSignature] public int Age { get; set; } @@ -150,7 +150,7 @@ class ObjectWithAllDomainSignatureProperty : Entity } - class ObjectWithAssignedId : EntityWithTypedId, IHasAssignedId + class ObjectWithAssignedId : Entity, IHasAssignedId { [DomainSignature] public string Name { get; set; } @@ -162,7 +162,7 @@ public void SetAssignedIdTo(string assignedId) } - class ObjectWithComplexProperties : Entity + class ObjectWithComplexProperties : Entity { [DomainSignature] public AddressBeingDomainSignatureComparable Address { get; set; } @@ -175,7 +175,7 @@ class ObjectWithComplexProperties : Entity } - class ObjectWithIdenticalTypedProperties : Entity + class ObjectWithIdenticalTypedProperties : Entity { [DomainSignature] public string Address { get; set; } @@ -185,7 +185,7 @@ class ObjectWithIdenticalTypedProperties : Entity } - class ObjectWithIntId : Entity + class ObjectWithIntId : Entity { [DomainSignature] public string Name { get; set; } @@ -196,7 +196,7 @@ class ObjectWithIntId : Entity /// This is a nonsense object; i.e., it doesn't make sense to have /// an entity without a domain signature. /// - class ObjectWithNoDomainSignatureProperties : Entity + class ObjectWithNoDomainSignatureProperties : Entity { public int Age { get; set; } @@ -227,7 +227,7 @@ public override int GetHashCode() } - class Contact : Entity + class Contact : Entity { public virtual string EmailAddress { get; set; } } @@ -423,14 +423,6 @@ public void CannotEquateObjectsWithSameIdButDifferentTypes() obj1.Equals(obj2).Should().BeFalse(); } - [Fact] - public void CanSerializeEntityToJson() - { - var obj1 = new Contact {EmailAddress = "serialize@this.net"}; - string result = JsonConvert.SerializeObject(obj1); - result.Should().Contain("serialize@this.net"); - } - [Fact] public void DoDefaultEntityEqualsOverrideWorkWhenIdIsAssigned() { @@ -514,33 +506,6 @@ public void obj.GetHashCode().Should().Be(hashcodeWhenTransient); } - [Fact] - public void EntitySerializesAsJsonProperly() - { - var obj = new ObjectWithOneDomainSignatureProperty(); - obj.SetIdTo(999); - obj.Age = 13; - obj.Name = "Foo"; - - var jsonSerializer = new JsonSerializer(); - - string jsonString; - using (var stringWriter = new StringWriter()) - { - jsonSerializer.Serialize(stringWriter, obj); - jsonString = stringWriter.ToString(); - } - - using (var stringReader = new StringReader(jsonString)) - { - using (var jsonReader = new JsonTextReader(stringReader)) - { - var deserialized = jsonSerializer.Deserialize(jsonReader); - deserialized.Should().BeEquivalentTo(obj); - } - } - } - [Fact] public void KeepsConsistentHashThroughLifetimeOfPersistentObject() { @@ -599,8 +564,8 @@ public void Transient_entity_without_domain_signature_should_return_consistent_h [Fact] public void Two_persistent_entities_with_different_domain_signature_and_equal_ids_generate_equal_hashcodes() { - IEntityWithTypedId obj1 = new ObjectWithOneDomainSignatureProperty {Age = 1}.SetIdTo(1); - IEntityWithTypedId obj2 = new ObjectWithOneDomainSignatureProperty {Age = 2}.SetIdTo(1); + IEntity obj1 = new ObjectWithOneDomainSignatureProperty {Age = 1}.SetIdTo(1); + IEntity obj2 = new ObjectWithOneDomainSignatureProperty {Age = 2}.SetIdTo(1); obj1.GetHashCode().Should().Be(obj2.GetHashCode()); } @@ -608,8 +573,8 @@ public void Two_persistent_entities_with_different_domain_signature_and_equal_id [Fact] public void Two_persistent_entities_with_equal_domain_signature_and_different_ids_generate_different_hashcodes() { - IEntityWithTypedId obj1 = new ObjectWithOneDomainSignatureProperty {Age = 1}.SetIdTo(1); - IEntityWithTypedId obj2 = new ObjectWithOneDomainSignatureProperty {Age = 1}.SetIdTo(2); + IEntity obj1 = new ObjectWithOneDomainSignatureProperty {Age = 1}.SetIdTo(1); + IEntity obj2 = new ObjectWithOneDomainSignatureProperty {Age = 1}.SetIdTo(2); obj1.GetHashCode().Should().NotBe(obj2.GetHashCode()); } @@ -618,8 +583,8 @@ public void Two_persistent_entities_with_equal_domain_signature_and_different_id public void Two_persistent_entities_with_no_signature_properties_and_different_ids_generate_different_hashcodes( ) { - IEntityWithTypedId obj1 = new ObjectWithNoDomainSignatureProperties().SetIdTo(1); - IEntityWithTypedId obj2 = new ObjectWithNoDomainSignatureProperties().SetIdTo(2); + IEntity obj1 = new ObjectWithNoDomainSignatureProperties().SetIdTo(1); + IEntity obj2 = new ObjectWithNoDomainSignatureProperties().SetIdTo(2); obj1.GetHashCode().Should().NotBe(obj2.GetHashCode()); } @@ -627,8 +592,8 @@ public void Two_persistent_entities_with_no_signature_properties_and_different_i [Fact] public void Two_persistent_entities_with_no_signature_properties_and_equal_ids_generate_equal_hashcodes() { - IEntityWithTypedId obj1 = new ObjectWithNoDomainSignatureProperties().SetIdTo(1); - IEntityWithTypedId obj2 = new ObjectWithNoDomainSignatureProperties().SetIdTo(1); + IEntity obj1 = new ObjectWithNoDomainSignatureProperties().SetIdTo(1); + IEntity obj2 = new ObjectWithNoDomainSignatureProperties().SetIdTo(1); obj1.GetHashCode().Should().Be(obj2.GetHashCode()); } diff --git a/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/TestEntities.cs b/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/TestEntities.cs index b889317ac..d9d6b4e56 100644 --- a/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/TestEntities.cs +++ b/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/TestEntities.cs @@ -8,7 +8,7 @@ namespace Tests.SharpArch.Domain [HasUniqueDomainSignature] - public class Contractor : Entity + public class Contractor : Entity { [DomainSignature] public virtual string Name { get; set; } @@ -16,7 +16,7 @@ public class Contractor : Entity [HasUniqueDomainSignature] - public class ObjectWithGuidId : EntityWithTypedId + public class ObjectWithGuidId : Entity { [DomainSignature] public virtual string Name { get; set; } @@ -24,7 +24,7 @@ public class ObjectWithGuidId : EntityWithTypedId [HasUniqueDomainSignature] - internal class ObjectWithStringIdAndValidatorForIntId : EntityWithTypedId + internal class ObjectWithStringIdAndValidatorForIntId : Entity { [DomainSignature] public virtual string Name { get; set; } @@ -32,7 +32,7 @@ internal class ObjectWithStringIdAndValidatorForIntId : EntityWithTypedId + public class User : Entity { [DomainSignature] public virtual string Ssn { get; set; } @@ -49,7 +49,7 @@ public User() } - internal class EntityWithNoDomainSignatureProperties : EntityWithTypedId + internal class EntityWithNoDomainSignatureProperties : Entity { public virtual string Property1 { get; set; } @@ -57,7 +57,7 @@ internal class EntityWithNoDomainSignatureProperties : EntityWithTypedId } - internal class EntityWithAllPropertiesPartOfDomainSignature : EntityWithTypedId + internal class EntityWithAllPropertiesPartOfDomainSignature : Entity { [DomainSignature] public virtual string Property1 { get; set; } @@ -70,7 +70,7 @@ internal class EntityWithAllPropertiesPartOfDomainSignature : EntityWithTypedId< } - internal class EntityWithSomePropertiesPartOfDomainSignature : EntityWithTypedId + internal class EntityWithSomePropertiesPartOfDomainSignature : Entity { [DomainSignature] public virtual string Property1 { get; set; } @@ -82,7 +82,7 @@ internal class EntityWithSomePropertiesPartOfDomainSignature : EntityWithTypedId } - internal class EntityWithAnotherEntityAsPartOfDomainSignature : EntityWithTypedId + internal class EntityWithAnotherEntityAsPartOfDomainSignature : Entity { [DomainSignature] public virtual string Property1 { get; set; } @@ -98,7 +98,7 @@ public EntityWithAnotherEntityAsPartOfDomainSignature() [HasUniqueDomainSignature] - public class Song : Entity + public class Song : Entity { [DomainSignature] public virtual string SongTitle { get; set; } @@ -109,7 +109,7 @@ public class Song : Entity [HasUniqueDomainSignature(ErrorMessage = "Band already exists")] - public class Band : Entity + public class Band : Entity { [DomainSignature] [Required] @@ -120,7 +120,7 @@ public class Band : Entity [HasUniqueDomainSignature(ErrorMessage = "Album already exists")] - public class Album : Entity + public class Album : Entity { [DomainSignature] [Required] @@ -139,7 +139,7 @@ public class Address : ValueObject [HasUniqueDomainSignature] - public class Customer : Entity + public class Customer : Entity { [DomainSignature] public virtual string Name { get; set; } diff --git a/VersionHistory.txt b/VersionHistory.txt index 5645d234c..62a5315d2 100644 --- a/VersionHistory.txt +++ b/VersionHistory.txt @@ -1,4 +1,13 @@ ======================== +vNext +======================== + +BREAKING: +* Removed EntityWithTypedId<> replaced with Entity<>, removed old entity class. Fix: replace `Entity` with `Entity`. +* Renamed IAsyncRepository to IRepository. +* Added IEquatable constraint on IEntity. + + S#arp 6.1.1 ======================== From 2e9295e6ad14b753f573c6b9a4bbd94c1188bded Mon Sep 17 00:00:00 2001 From: Vitaliy K Date: Sun, 10 Jan 2021 18:30:27 -0500 Subject: [PATCH 02/13] Remove .NET Core 2.2 as it reached end of life, closes #227 (#234) +semver:major --- Directory.Build.props | 2 +- .../Suteki.TardisBank.Tests/Suteki.TardisBank.Tests.csproj | 5 ----- Samples/TardisBank/Src/Suteki.TardisBank.WebApi/Startup.cs | 4 +--- .../Suteki.TardisBank.WebApi.csproj | 7 +------ Samples/TransactionAttribute/App/Startup.cs | 5 +---- .../App/TransactionAttribute.WebApi.csproj | 4 ---- .../Tests/TransactionAttribute.Tests.csproj | 5 ----- .../SharpArch.Web.AspNetCore.csproj | 7 ------- appveyor.yml | 1 - 9 files changed, 4 insertions(+), 36 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 319465834..e448b358e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -16,7 +16,7 @@ - netcoreapp2.1;netcoreapp2.2;netcoreapp3.1;net5 + netcoreapp2.1;netcoreapp3.1;net5 diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Suteki.TardisBank.Tests.csproj b/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Suteki.TardisBank.Tests.csproj index b23d21ccd..7d7abfea4 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Suteki.TardisBank.Tests.csproj +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Suteki.TardisBank.Tests.csproj @@ -24,11 +24,6 @@ - - - - - diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.WebApi/Startup.cs b/Samples/TardisBank/Src/Suteki.TardisBank.WebApi/Startup.cs index c381c0721..42dc357b2 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.WebApi/Startup.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.WebApi/Startup.cs @@ -18,7 +18,7 @@ namespace Suteki.TardisBank.WebApi using SharpArch.NHibernate.Impl; using SharpArch.Web.AspNetCore.Transaction; -#if NETCOREAPP2_1 || NETCOREAPP2_2 +#if NETCOREAPP2_1 using System.Globalization; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; @@ -63,8 +63,6 @@ public void ConfigureServices(IServiceCollection services) .AddJsonFormatters() #if NETCOREAPP2_1 .SetCompatibilityVersion(CompatibilityVersion.Version_2_1) -#elif NETCOREAPP2_2 - .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) #endif ; #endif diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.WebApi/Suteki.TardisBank.WebApi.csproj b/Samples/TardisBank/Src/Suteki.TardisBank.WebApi/Suteki.TardisBank.WebApi.csproj index ca88f8b1b..702a92e00 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.WebApi/Suteki.TardisBank.WebApi.csproj +++ b/Samples/TardisBank/Src/Suteki.TardisBank.WebApi/Suteki.TardisBank.WebApi.csproj @@ -22,13 +22,8 @@ - - - - - - + diff --git a/Samples/TransactionAttribute/App/Startup.cs b/Samples/TransactionAttribute/App/Startup.cs index 1d69eb0fc..6aa30ecb9 100644 --- a/Samples/TransactionAttribute/App/Startup.cs +++ b/Samples/TransactionAttribute/App/Startup.cs @@ -8,7 +8,7 @@ using Microsoft.Extensions.DependencyInjection; using SharpArch.Web.AspNetCore.Transaction; using Stubs; -#if NETCOREAPP2_1 || NETCOREAPP2_2 +#if NETCOREAPP2_1 using System.Globalization; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; @@ -37,7 +37,6 @@ public void ConfigureServices(IServiceCollection services) options.Filters.Add(new TransactionAttribute(isolationLevel: IsolationLevel.Chaos)); }) ; - #else // Add framework services. services.AddMvcCore(options => @@ -56,8 +55,6 @@ public void ConfigureServices(IServiceCollection services) .AddJsonFormatters() #if NETCOREAPP2_1 .SetCompatibilityVersion(CompatibilityVersion.Version_2_1) -#elif NETCOREAPP2_2 - .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) #endif ; #endif diff --git a/Samples/TransactionAttribute/App/TransactionAttribute.WebApi.csproj b/Samples/TransactionAttribute/App/TransactionAttribute.WebApi.csproj index 9dea86139..d37d0ff3d 100644 --- a/Samples/TransactionAttribute/App/TransactionAttribute.WebApi.csproj +++ b/Samples/TransactionAttribute/App/TransactionAttribute.WebApi.csproj @@ -18,10 +18,6 @@ - - - - diff --git a/Samples/TransactionAttribute/Tests/TransactionAttribute.Tests.csproj b/Samples/TransactionAttribute/Tests/TransactionAttribute.Tests.csproj index a86e8d86b..544feaa51 100644 --- a/Samples/TransactionAttribute/Tests/TransactionAttribute.Tests.csproj +++ b/Samples/TransactionAttribute/Tests/TransactionAttribute.Tests.csproj @@ -23,11 +23,6 @@ - - - - - diff --git a/Src/SharpArch.Web.AspNetCore/SharpArch.Web.AspNetCore.csproj b/Src/SharpArch.Web.AspNetCore/SharpArch.Web.AspNetCore.csproj index 5067d1cb0..5ae57636d 100644 --- a/Src/SharpArch.Web.AspNetCore/SharpArch.Web.AspNetCore.csproj +++ b/Src/SharpArch.Web.AspNetCore/SharpArch.Web.AspNetCore.csproj @@ -31,13 +31,6 @@ - - - - - - - diff --git a/appveyor.yml b/appveyor.yml index e7581d621..077e57a60 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -32,7 +32,6 @@ cache: - c:\tmp\cake\tools -> appveyor.yml install: - - ps: ./dotnet-install.ps1 -Version 2.2.100 -InstallDir "C:\Program Files\dotnet" - ps: ./mssql-setup.ps1 - ps: dotnet tool install Cake.Tool --version 1.1.0 --global From 8b0284f2ccf0917f5f946d7f79a9f0c5715c9213 Mon Sep 17 00:00:00 2001 From: Vitaliy K Date: Sun, 10 Jan 2021 19:26:40 -0500 Subject: [PATCH 03/13] Remove NHibernate configuration cache, closes #228 (#235) --- Src/Common/NHibernate/TestDatabaseSetup.cs | 27 +-- .../Abstractions/FileSystem.cs | 32 --- .../Abstractions/IFileSystem.cs | 25 --- .../Caching/DependencyList.cs | 194 ---------------- .../CodeBaseLocator.cs | 34 +++ .../SharpArch.Infrastructure.csproj | 4 + .../ConfigurationFileCache.cs | 125 ----------- .../AutomappingConfiguration.cs | 11 +- .../INHibernateConfigurationCache.cs | 30 --- .../NHibernateConfigurationCacheBase.cs | 124 ---------- .../NHibernateConfigurationFileCache.cs | 44 ---- .../NHibernateSessionFactoryBuilder.cs | 64 +----- .../NullNHibernateConfigurationCache.cs | 32 --- .../NHibernateSessionFactoryBuilderTests.cs | 81 +------ .../NHibernateSessionFactoryBuilderTests.cs | 212 ------------------ .../DependencyListTests.cs | 95 -------- .../DependencyListTests_RealFileSystem.cs | 59 ----- 17 files changed, 66 insertions(+), 1127 deletions(-) delete mode 100644 Src/SharpArch.Infrastructure/Abstractions/FileSystem.cs delete mode 100644 Src/SharpArch.Infrastructure/Abstractions/IFileSystem.cs delete mode 100644 Src/SharpArch.Infrastructure/Caching/DependencyList.cs create mode 100644 Src/SharpArch.Infrastructure/CodeBaseLocator.cs delete mode 100644 Src/SharpArch.NHibernate/ConfigurationFileCache.cs delete mode 100644 Src/SharpArch.NHibernate/INHibernateConfigurationCache.cs delete mode 100644 Src/SharpArch.NHibernate/NHibernateConfigurationCacheBase.cs delete mode 100644 Src/SharpArch.NHibernate/NHibernateConfigurationFileCache.cs delete mode 100644 Src/SharpArch.NHibernate/NullNHibernateConfigurationCache.cs delete mode 100644 Src/Tests/SharpArch.XunitTests.NHibernate/NHibernateSessionFactoryBuilderTests.cs delete mode 100644 Src/Tests/SharpArch.XunitTests/SharpArch.Infrastructure/DependencyListTests.cs delete mode 100644 Src/Tests/SharpArch.XunitTests/SharpArch.Infrastructure/DependencyListTests_RealFileSystem.cs diff --git a/Src/Common/NHibernate/TestDatabaseSetup.cs b/Src/Common/NHibernate/TestDatabaseSetup.cs index 245c547e7..9a0b2b0d2 100644 --- a/Src/Common/NHibernate/TestDatabaseSetup.cs +++ b/Src/Common/NHibernate/TestDatabaseSetup.cs @@ -9,7 +9,7 @@ using global::NHibernate; using global::NHibernate.Cfg; using global::NHibernate.Tool.hbm2ddl; - using Infrastructure.Caching; + using Infrastructure; using JetBrains.Annotations; using SharpArch.NHibernate; using SharpArch.NHibernate.FluentNHibernate; @@ -25,10 +25,10 @@ [PublicAPI] public class TestDatabaseSetup : IDisposable { - readonly string _basePath; - readonly Assembly[] _mappingAssemblies; - Configuration _configuration; - ISessionFactory _sessionFactory; + [NotNull] readonly string _basePath; + [NotNull] readonly Assembly[] _mappingAssemblies; + [CanBeNull] Configuration _configuration; + [CanBeNull] ISessionFactory _sessionFactory; /// /// Initializes a new instance of the class. @@ -61,7 +61,7 @@ public TestDatabaseSetup([NotNull] string basePath, [NotNull] Assembly[] mapping /// null. /// public TestDatabaseSetup([NotNull] Assembly baseAssembly, [NotNull] Assembly[] mappingAssemblies) - : this(DependencyList.GetAssemblyCodeBasePath(baseAssembly), + : this(CodeBaseLocator.GetAssemblyCodeBasePath(baseAssembly), mappingAssemblies) { } @@ -93,6 +93,7 @@ public virtual void Dispose() /// allowed. /// /// Unable to instantiate AutoPersistenceModelGenerator. + [NotNull] public static AutoPersistenceModel GenerateAutoPersistenceModel([NotNull] Assembly[] assemblies) { if (assemblies == null) throw new ArgumentNullException(nameof(assemblies)); @@ -158,7 +159,7 @@ public Configuration GetConfiguration() /// /// /// - protected virtual void Customize(NHibernateSessionFactoryBuilder builder) + protected virtual void Customize([NotNull] NHibernateSessionFactoryBuilder builder) { } @@ -171,7 +172,7 @@ public ISessionFactory GetSessionFactory() { if (_sessionFactory != null) return _sessionFactory; _sessionFactory = GetConfiguration().BuildSessionFactory(); - return _sessionFactory; + return _sessionFactory!; } /// @@ -214,17 +215,17 @@ public static void Shutdown([CanBeNull] ISessionFactory sessionFactory) /// /// /// - static Assembly TryLoadAssembly(string assemblyPath) - { - return Assembly.LoadFrom(assemblyPath); - } + [NotNull] + static Assembly TryLoadAssembly([NotNull] string assemblyPath) + => Assembly.LoadFrom(assemblyPath); /// /// Adds dll extension to assembly name if required. /// /// Name of the assembly. /// - static string EnsureDllExtension(string assemblyName) + [NotNull] + static string EnsureDllExtension([NotNull] string assemblyName) { assemblyName = assemblyName.Trim(); const string dllExtension = ".dll"; diff --git a/Src/SharpArch.Infrastructure/Abstractions/FileSystem.cs b/Src/SharpArch.Infrastructure/Abstractions/FileSystem.cs deleted file mode 100644 index d895ab803..000000000 --- a/Src/SharpArch.Infrastructure/Abstractions/FileSystem.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace SharpArch.Infrastructure.Abstractions -{ - using System; - using System.IO; - - - /// - /// File system abstraction. - /// - public class FileSystem : IFileSystem - { - /// - /// Determines whether specified file exists. - /// - /// - /// - public bool FileExists(string path) - { - return File.Exists(path); - } - - /// - /// Returns time when file or directory was last written to. - /// - /// - /// - public DateTime GetLastWriteTimeUtc(string path) - { - return File.GetLastWriteTimeUtc(path); - } - } -} diff --git a/Src/SharpArch.Infrastructure/Abstractions/IFileSystem.cs b/Src/SharpArch.Infrastructure/Abstractions/IFileSystem.cs deleted file mode 100644 index e650351f7..000000000 --- a/Src/SharpArch.Infrastructure/Abstractions/IFileSystem.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace SharpArch.Infrastructure.Abstractions -{ - using System; - - - /// - /// File system abstraction. - /// - public interface IFileSystem - { - /// - /// Determines whether specified file exists. - /// - /// - /// - bool FileExists(string path); - - /// - /// Returns time when file or directory was last written to. - /// - /// - /// - DateTime GetLastWriteTimeUtc(string path); - } -} diff --git a/Src/SharpArch.Infrastructure/Caching/DependencyList.cs b/Src/SharpArch.Infrastructure/Caching/DependencyList.cs deleted file mode 100644 index 965f86d96..000000000 --- a/Src/SharpArch.Infrastructure/Caching/DependencyList.cs +++ /dev/null @@ -1,194 +0,0 @@ -namespace SharpArch.Infrastructure.Caching -{ - using System; - using System.Collections.Generic; - using System.IO; - using System.Linq; - using System.Reflection; - using Abstractions; - using JetBrains.Annotations; - - - /// - /// Resolves and collects file dependencies. - /// Use to get latest modification timestamp of dependency list. - /// - public class DependencyList - { - private readonly List _fileDependencies = new List(16); - - private readonly IFileSystem _fileSystem; - private string _basePath; - - public static DependencyList WithPathPrefix([NotNull] string basePath, IFileSystem fileSystem = null) - { - if (string.IsNullOrEmpty(basePath)) throw new ArgumentException("Value cannot be null or empty.", nameof(basePath)); - return new DependencyList(fileSystem ?? new FileSystem(), basePath); - } - - public static DependencyList WithBasePathOfAssembly([NotNull] Assembly assembly, IFileSystem fileSystem = null) - { - if (assembly == null) throw new ArgumentNullException(nameof(assembly)); - return WithPathPrefix(GetAssemblyCodeBasePath(assembly), fileSystem); - } - - /// - /// Constructor. - /// - /// Custom file system. - /// Base directory to use for file path resolution. - public DependencyList([NotNull] IFileSystem fileSystem, [NotNull] string basePath) - { - if (string.IsNullOrEmpty(basePath)) throw new ArgumentException("Value cannot be null or empty.", nameof(basePath)); - _fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem)); - _basePath = basePath; - } - - /// - /// Add assembly containing given type. - /// - /// Type - /// Self - /// Type is dynamically generated (assembly does not exists on disk). - public DependencyList AddAssemblyOf() - { - var assembly = typeof(TType).Assembly; - return AddAssembly(assembly); - } - - /// - /// Adds assembly to dependency list. - /// - /// Assembly - /// Assembly is dynamically generated. - /// Self - public DependencyList AddAssembly(Assembly assembly) - { - if (assembly.IsDynamic) - throw new InvalidOperationException($"Cannot get location for dynamically created assembly '{assembly.GetName().Name}'"); - _fileDependencies.Add(assembly.Location); - return this; - } - - /// - /// Adds multiple assemblies to dependency list. - /// - /// List of assemblies. - /// Assembly list contains dynamically generated assembly. - /// Self - public DependencyList AddAssemblies([NotNull] IEnumerable assemblies) - { - if (assemblies == null) throw new ArgumentNullException(nameof(assemblies)); - foreach (var assembly in assemblies) AddAssembly(assembly); - - return this; - } - - /// - /// Adds file to dependency list. - /// - /// File path, if relative, base path will be used as root. - /// Self - /// is null or whitespace. - public DependencyList AddFile([NotNull] string fileName) - { - if (string.IsNullOrWhiteSpace(fileName)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(fileName)); - - _fileDependencies.Add(FindFile(fileName)); - return this; - } - - /// - /// Adds files to dependency list. is performed for each dependency. - /// - /// List of files. - /// Self - public DependencyList AddFiles([NotNull] IEnumerable files) - { - if (files == null) throw new ArgumentNullException(nameof(files)); - foreach (var fileName in files) AddFile(fileName); - - return this; - } - - private string GetCodeBasePath() - { - return _basePath ?? (_basePath = GetAssemblyCodeBasePath(Assembly.GetExecutingAssembly())); - } - - /// - /// Returns directory of assembly code base. - /// - /// Assembly - /// Directory path - /// is - [NotNull] - public static string GetAssemblyCodeBasePath([NotNull] Assembly assembly) - { - if (assembly == null) throw new ArgumentNullException(nameof(assembly)); - - string path = null; -#if NET5_0 - path = assembly.Location; -#else - var uri = new UriBuilder(assembly.CodeBase); - path = Uri.UnescapeDataString(uri.Path); -#endif - return Path.GetDirectoryName(path); - } - - /// - /// Tests if the file or assembly name exists either in the application's bin folder - /// or elsewhere. - /// - /// Path or file name to test for existence. - /// Full path of the file. - /// - /// If the path parameter does not end with ".dll" it is appended and - /// tested if the dll file exists. - /// - /// Thrown if the file is not found. - private string FindFile(string path) - { - var codeLocation = GetCodeBasePath(); - - // add base path to relative path - var codePath = Path.IsPathRooted(path) - ? path - : Path.Combine(codeLocation, path); - if (_fileSystem.FileExists(codePath)) return codePath; - - // try with .dll extension added - var dllPath = path.IndexOf(".dll", StringComparison.InvariantCultureIgnoreCase) == -1 - ? path + ".dll" - : path; - if (_fileSystem.FileExists(dllPath)) return dllPath; - - // try with .dll extension and base path - var codeDllPath = Path.Combine(codeLocation, dllPath); - if (_fileSystem.FileExists(codeDllPath)) return codeDllPath; - - throw new FileNotFoundException("Unable to find file.", path); - } - - /// - /// Return list of dependencies. - /// - /// - public string[] Build() - { - return _fileDependencies.Distinct().ToArray(); - } - - /// - /// Gets latest modification time of all dependencies. - /// - /// - public DateTime? GetLastModificationTime() - { - return _fileDependencies.Count == 0 - ? (DateTime?) null - : _fileDependencies.Distinct().Select(fn => _fileSystem.GetLastWriteTimeUtc(fn)).Max(); - } - } -} diff --git a/Src/SharpArch.Infrastructure/CodeBaseLocator.cs b/Src/SharpArch.Infrastructure/CodeBaseLocator.cs new file mode 100644 index 000000000..ae04c3fe8 --- /dev/null +++ b/Src/SharpArch.Infrastructure/CodeBaseLocator.cs @@ -0,0 +1,34 @@ +namespace SharpArch.Infrastructure +{ + using System; + using System.IO; + using System.Reflection; + using JetBrains.Annotations; + + + /// + /// Resolves assembly code base directory. + /// + [PublicAPI] + public class CodeBaseLocator + { + /// + /// Returns directory of assembly code base. + /// + /// Assembly + /// Directory path + /// is + [NotNull] + public static string GetAssemblyCodeBasePath([NotNull] Assembly assembly) + { + if (assembly == null) throw new ArgumentNullException(nameof(assembly)); +#if NET5_0 + var uri = new UriBuilder(assembly.Location); +#else + var uri = new UriBuilder(assembly.CodeBase); +#endif + var uriPath = Uri.UnescapeDataString(uri.Path); + return Path.GetDirectoryName(uriPath); + } + } +} diff --git a/Src/SharpArch.Infrastructure/SharpArch.Infrastructure.csproj b/Src/SharpArch.Infrastructure/SharpArch.Infrastructure.csproj index d83e240c2..fac7392f0 100644 --- a/Src/SharpArch.Infrastructure/SharpArch.Infrastructure.csproj +++ b/Src/SharpArch.Infrastructure/SharpArch.Infrastructure.csproj @@ -32,5 +32,9 @@ + + + + diff --git a/Src/SharpArch.NHibernate/ConfigurationFileCache.cs b/Src/SharpArch.NHibernate/ConfigurationFileCache.cs deleted file mode 100644 index 196cd879d..000000000 --- a/Src/SharpArch.NHibernate/ConfigurationFileCache.cs +++ /dev/null @@ -1,125 +0,0 @@ -namespace SharpArch.NHibernate -{ - using System; - using System.Diagnostics; - using System.IO; - using System.Runtime.Serialization; - using System.Runtime.Serialization.Formatters.Binary; - using System.Security; - using global::NHibernate.Cfg; - using JetBrains.Annotations; - using global::FluentNHibernate.Infrastructure; - - - - /// - /// Provides file cache helper methods. - /// - static class ConfigurationFileCache - { - /// - /// Loads NHibernate configuration from file. - /// - /// Full path to file containing serialized data. - /// instance, or null in case of deserialization error. - /// Thrown if the path parameter is null or empty. - public static Configuration RetrieveFromCache(string path) - { - if (string.IsNullOrEmpty(path)) - { - throw new ArgumentNullException(nameof(path)); - } - - try - { - using (FileStream file = File.Open(path, FileMode.Open)) - { - return Load(file); - } - } - // ReSharper disable once CatchAllClause - catch (Exception ex) - { - Debug.WriteLine(ex, "ConfigurationFileCache"); - // Return null if the object can't be deserialized - return null; - } - } - - /// - /// Serializes NHibernate configuration to a file at the given path. - /// - /// NHibernate configuration instance. - /// Full path of file to store the serialized data. - /// Thrown if configuration or path parameters are null. - /// - /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters. - /// - /// - /// The specified path, file name, or both exceed the system-defined maximum length. - /// For example, on Windows-based platforms, paths must be less than 248 characters, and file names must be less than - /// 260 characters. - /// - /// is in an invalid format. - /// The specified path is invalid, (for example, it is on an unmapped drive). - /// An I/O error occurred while opening the file. - /// - /// specified a file that is read-only. - /// -or- This operation is not supported on the current platform. - /// -or- specified a directory. - /// -or- The caller does not have the required permission. - /// -or specified file is a hidden file. - /// - /// The caller does not have the required permission. - /// - /// An error has occurred during serialization, such as if an object in the parameter is not - /// marked as serializable. - /// - public static void StoreInCache([NotNull] Configuration configuration, [NotNull] string path) - { - if (configuration == null) throw new ArgumentNullException(nameof(configuration)); - if (string.IsNullOrEmpty(path)) throw new ArgumentException("Path is null or empty.", nameof(path)); - using (FileStream file = File.Open(path, FileMode.Create)) - { - Save(file, configuration); - } - } - - /// - /// Saves object to stream in BinaryFormat. - /// - /// The stream. - /// Configuration. - /// - /// An error has occurred during serialization, such as if an object in the parameter is not - /// marked as serializable. - /// - /// The caller does not have the required permission. - internal static void Save([NotNull] Stream stream, Configuration configuration) - { - CreateFormatter().Serialize(stream, configuration); - } - - static BinaryFormatter CreateFormatter() - { - return new BinaryFormatter(new NetStandardSerialization.SurrogateSelector(), new StreamingContext()); - } - - /// - /// Load object from the stream. - /// - /// The stream. - /// instance. - /// - /// The supports seeking, but its length is 0. - /// -or-The target type is a , but the value is out of range of the - /// type. - /// - /// The caller does not have the required permission. - internal static Configuration Load([NotNull] Stream stream) - { - return CreateFormatter().Deserialize(stream) as Configuration; - } - } -} diff --git a/Src/SharpArch.NHibernate/FluentNHibernate/AutomappingConfiguration.cs b/Src/SharpArch.NHibernate/FluentNHibernate/AutomappingConfiguration.cs index 4e3a699a5..548591a71 100644 --- a/Src/SharpArch.NHibernate/FluentNHibernate/AutomappingConfiguration.cs +++ b/Src/SharpArch.NHibernate/FluentNHibernate/AutomappingConfiguration.cs @@ -46,18 +46,13 @@ public override bool ShouldMap(Type type) /// See https://martinfowler.com/eaaCatalog/valueObject.html /// public override bool IsComponent(Type type) - { - return typeof(ValueObject).IsAssignableFrom(type); - } + => typeof(ValueObject).IsAssignableFrom(type); /// - /// Marks all abstract descendants of and - /// as Layer Supertype. + /// Marks all abstract descendants of as Layer Supertype. /// See http://martinfowler.com/eaaCatalog/layerSupertype.html /// public override bool AbstractClassIsLayerSupertype(Type type) - { - return type == typeof(Entity<>); - } + => type == typeof(Entity<>); } } diff --git a/Src/SharpArch.NHibernate/INHibernateConfigurationCache.cs b/Src/SharpArch.NHibernate/INHibernateConfigurationCache.cs deleted file mode 100644 index ebc1b34e2..000000000 --- a/Src/SharpArch.NHibernate/INHibernateConfigurationCache.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace SharpArch.NHibernate -{ - using System; - using global::NHibernate.Cfg; - using JetBrains.Annotations; - - - /// - /// Interface for providing caching capability for an object. - /// - [PublicAPI] - public interface INHibernateConfigurationCache - { - /// - /// Load the object from a cache. - /// - /// - /// If an up to date cached object is available, a object, otherwise null. - /// - [CanBeNull] - Configuration TryLoad(DateTime localConfigurationTimestampUtc); - - /// - /// Save the object to a cache. - /// - /// Configuration object to save. - /// Configuration modification date. - void Save([NotNull] Configuration configuration, DateTime timestampUtc); - } -} diff --git a/Src/SharpArch.NHibernate/NHibernateConfigurationCacheBase.cs b/Src/SharpArch.NHibernate/NHibernateConfigurationCacheBase.cs deleted file mode 100644 index c1ce7676b..000000000 --- a/Src/SharpArch.NHibernate/NHibernateConfigurationCacheBase.cs +++ /dev/null @@ -1,124 +0,0 @@ -namespace SharpArch.NHibernate -{ - using System; - using System.IO; - using System.Runtime.Serialization; - using System.Runtime.Serialization.Formatters.Binary; - using global::FluentNHibernate.Infrastructure; - using global::NHibernate.Cfg; - using global::NHibernate.UserTypes; - using Infrastructure.Logging; - using JetBrains.Annotations; - - - /// - /// File cache implementation of INHibernateConfigurationCache. Saves and loads a - /// serialized version of to a temporary file location. - /// - /// - /// Serializing a object requires that all components - /// that make up the Configuration object be Serializable. This includes any custom NHibernate - /// user types implementing . - /// - [PublicAPI] - public abstract class NHibernateConfigurationCacheBase : INHibernateConfigurationCache - { - private static readonly ILog Log = LogProvider.For(); - private readonly string _sessionName; - - /// - protected NHibernateConfigurationCacheBase([NotNull] string sessionName) - { - _sessionName = sessionName ?? throw new ArgumentNullException(nameof(sessionName)); - } - - /// - public Configuration TryLoad(DateTime localConfigurationTimestampUtc) - { - try - { - var cachedTimestampUtc = GetCachedTimestampUtc(); - if (cachedTimestampUtc.HasValue && cachedTimestampUtc.Value >= localConfigurationTimestampUtc) - { - var cachedConfig = GetCachedConfiguration(); - if (cachedConfig != null) - { - using (var ms = new MemoryStream(cachedConfig, false)) - { - Log.InfoFormat("Using cached configuration for {session}", _sessionName); - return (Configuration) CreateSerializer().Deserialize(ms); - } - } - } - - Log.InfoFormat("Cached configuration for {session} does not exists for outdated - {cachedTimestampUtc}", - _sessionName, cachedTimestampUtc); - return null; - } - // ReSharper disable once CatchAllClause - catch (Exception ex) - { - Log.WarnException("Error retrieving cached configuration for {session}, session configuration will be created", ex, _sessionName); - return null; - } - } - - /// - public void Save(Configuration configuration, DateTime timestampUtc) - { - if (configuration == null) throw new ArgumentNullException(nameof(configuration)); - if (timestampUtc == DateTime.MinValue) throw new ArgumentException("Invalid date", nameof(timestampUtc)); - try - { - using (var ms = new MemoryStream(64 * 1024)) - { - CreateSerializer().Serialize(ms, configuration); - var data = ms.ToArray(); - SaveConfiguration(data, timestampUtc); - } - } - catch (Exception ex) - { - Log.WarnException("Error saving configuration for {session} to cache", ex, _sessionName); - } - } - - /// - /// Reads serialized configuration from cache. - /// - /// Configuration as byte array or null if configuration is not available in cache. - /// - /// Exception thrown by this method will be handled by . - /// - [CanBeNull] - protected abstract byte[] GetCachedConfiguration(); - - /// - /// Returns modification of the configuration (most recent file modification date). - /// This timestamp is used to compare local configuration files against cached configuration. - /// - /// Timestamp is UTC or null if cached configuration is not available. - protected abstract DateTime? GetCachedTimestampUtc(); - - /// - /// Stores serialized configuration in cache. - /// - /// Serialized configuration. - /// Timestamp of configuration. - protected abstract void SaveConfiguration(byte[] data, DateTime timestampUtc); - - /// - /// Creates binary serializer for NHibernate configuration. - /// - /// - /// - /// - /// - /// Override this method to provide custom serializers for NHibernate configuration classes. - /// - protected virtual BinaryFormatter CreateSerializer() - { - return new BinaryFormatter(new NetStandardSerialization.SurrogateSelector(), new StreamingContext()); - } - } -} diff --git a/Src/SharpArch.NHibernate/NHibernateConfigurationFileCache.cs b/Src/SharpArch.NHibernate/NHibernateConfigurationFileCache.cs deleted file mode 100644 index 9e925115b..000000000 --- a/Src/SharpArch.NHibernate/NHibernateConfigurationFileCache.cs +++ /dev/null @@ -1,44 +0,0 @@ -namespace SharpArch.NHibernate -{ - using System; - using System.IO; - using JetBrains.Annotations; - - - /// - /// File-based NHibernate configuration cache. - /// - public class NHibernateConfigurationFileCache : NHibernateConfigurationCacheBase - { - private string _fileName; - - /// - public NHibernateConfigurationFileCache([NotNull] string sessionName, [NotNull] string fileName) - : base(sessionName) - { - if (string.IsNullOrWhiteSpace(fileName)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(fileName)); - _fileName = Path.Combine(Path.GetTempPath(), fileName); - } - - /// - protected override byte[] GetCachedConfiguration() - { - return File.Exists(_fileName) - ? File.ReadAllBytes(_fileName) - : null; - } - - /// - protected override DateTime? GetCachedTimestampUtc() - { - return File.Exists(_fileName) ? File.GetLastWriteTimeUtc(_fileName) : (DateTime?) null; - } - - /// - protected override void SaveConfiguration(byte[] data, DateTime timestampUtc) - { - File.WriteAllBytes(_fileName, data); - File.SetLastWriteTimeUtc(_fileName, timestampUtc); - } - } -} diff --git a/Src/SharpArch.NHibernate/NHibernateSessionFactoryBuilder.cs b/Src/SharpArch.NHibernate/NHibernateSessionFactoryBuilder.cs index 22587ed69..72ccedab3 100644 --- a/Src/SharpArch.NHibernate/NHibernateSessionFactoryBuilder.cs +++ b/Src/SharpArch.NHibernate/NHibernateSessionFactoryBuilder.cs @@ -10,7 +10,6 @@ using global::FluentNHibernate.Cfg.Db; using global::NHibernate; using global::NHibernate.Cfg; - using Infrastructure.Caching; using JetBrains.Annotations; using NHibernateValidator; @@ -40,7 +39,6 @@ public class NHibernateSessionFactoryBuilder AutoPersistenceModel _autoPersistenceModel; string _configFile; - INHibernateConfigurationCache _configurationCache; Action _exposeConfiguration; IPersistenceConfigurer _persistenceConfigurer; IDictionary _properties; @@ -52,9 +50,7 @@ public class NHibernateSessionFactoryBuilder /// public NHibernateSessionFactoryBuilder() { - _configurationCache = NullNHibernateConfigurationCache.Null; _mappingAssemblies = new List(8); - _additionalDependencies = new List(8); } /// @@ -71,10 +67,6 @@ public ISessionFactory BuildSessionFactory() /// /// Builds NHibernate configuration. /// - /// - /// Base directory to use for loading additional files. - /// If null base folder of the current assembly is used. - /// /// /// /// Any changes made to configuration object after this point will not be persisted in configuration cache. @@ -87,28 +79,10 @@ public ISessionFactory BuildSessionFactory() /// /// No dependencies were specified [NotNull] - public Configuration BuildConfiguration(string basePath = null) + public Configuration BuildConfiguration() { - var dependencyList = basePath == null - ? DependencyList.WithBasePathOfAssembly(Assembly.GetExecutingAssembly()) - : DependencyList.WithPathPrefix(basePath); - dependencyList - .AddAssemblies(_mappingAssemblies); - - if (!string.IsNullOrEmpty(_configFile)) dependencyList.AddFile(_configFile); - dependencyList.AddFiles(_additionalDependencies); - - var timestamp = dependencyList.GetLastModificationTime(); - if (timestamp == null) throw new InvalidOperationException("No dependencies were specified"); - - var configuration = _configurationCache.TryLoad(timestamp.Value); - - if (configuration == null) - { - configuration = LoadExternalConfiguration(); - configuration = ApplyCustomSettings(configuration); - _configurationCache.Save(configuration, timestamp.Value); - } + var configuration = LoadExternalConfiguration(); + configuration = ApplyCustomSettings(configuration); return configuration; } @@ -132,20 +106,6 @@ bool ShouldExposeConfiguration() return _exposeConfiguration != null; } - /// - /// Allows to cache compiled NHibernate configuration. - /// - /// The configuration cache, see . - /// - /// Please provide configuration cache instance. - [NotNull] - public NHibernateSessionFactoryBuilder UseConfigurationCache( - [NotNull] INHibernateConfigurationCache configurationCache) - { - _configurationCache = configurationCache ?? - throw new ArgumentNullException(nameof(configurationCache), "Please provide configuration cache instance."); - return this; - } /// /// Allows to specify additional assemblies containing FluentNHibernate mappings. @@ -162,24 +122,6 @@ public NHibernateSessionFactoryBuilder AddMappingAssemblies([NotNull] IEnumerabl return this; } - /// - /// Add generic file dependency. - /// Used with session cache to add dependency which is not used to configure session - /// (e.g. application configuration, shared library, etc...) - /// - /// File name - /// - /// File name cannot be empty - public NHibernateSessionFactoryBuilder WithFileDependency([NotNull] string fileName) - { - if (string.IsNullOrWhiteSpace(fileName)) - { - throw new ArgumentException("File name cannot be empty", nameof(fileName)); - } - - _additionalDependencies.Add(fileName); - return this; - } /// /// Allows to specify FluentNhibernate auto-persistence model to use.. diff --git a/Src/SharpArch.NHibernate/NullNHibernateConfigurationCache.cs b/Src/SharpArch.NHibernate/NullNHibernateConfigurationCache.cs deleted file mode 100644 index acbf4bb9d..000000000 --- a/Src/SharpArch.NHibernate/NullNHibernateConfigurationCache.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace SharpArch.NHibernate -{ - using System; - using global::NHibernate.Cfg; - - - /// - /// Null Object for configuration cache. - /// - internal class NullNHibernateConfigurationCache : INHibernateConfigurationCache - { - /// - /// Instance. - /// - public static readonly INHibernateConfigurationCache Null = new NullNHibernateConfigurationCache(); - - private NullNHibernateConfigurationCache() - { - } - - /// - public Configuration TryLoad(DateTime localConfigurationTimestampUtc) - { - return null; - } - - /// - public void Save(Configuration configuration, DateTime timestampUtc) - { - } - } -} diff --git a/Src/Tests/SharpArch.Tests.NHibernate/NHibernateSessionFactoryBuilderTests.cs b/Src/Tests/SharpArch.Tests.NHibernate/NHibernateSessionFactoryBuilderTests.cs index abd574d56..65e67453b 100644 --- a/Src/Tests/SharpArch.Tests.NHibernate/NHibernateSessionFactoryBuilderTests.cs +++ b/Src/Tests/SharpArch.Tests.NHibernate/NHibernateSessionFactoryBuilderTests.cs @@ -1,32 +1,21 @@ namespace Tests.SharpArch.NHibernate { using System; - using System.Collections.Generic; using System.IO; using FluentAssertions; using FluentNHibernate.Cfg.Db; using global::NHibernate.Cfg; using global::SharpArch.NHibernate; - using JetBrains.Annotations; using NUnit.Framework; [TestFixture] class NHibernateSessionFactoryBuilderTests { - private string _tempFileName; - - static string GetConfigFullName() - { - const string defaultConfigFile = "sqlite-nhibernate-config.xml"; - return Path.Combine(TestContext.CurrentContext.TestDirectory, defaultConfigFile); - } - [SetUp] public void SetUp() { _tempFileName = "SharpArch.Tests." + Guid.NewGuid().ToString("D") + ".tmp"; - } [TearDown] @@ -43,6 +32,14 @@ public void TearDown() } } + string _tempFileName; + + static string GetConfigFullName() + { + const string defaultConfigFile = "sqlite-nhibernate-config.xml"; + return Path.Combine(TestContext.CurrentContext.TestDirectory, defaultConfigFile); + } + [Test] public void CanExposeConfiguration() { @@ -77,8 +74,6 @@ public void CanInitializeWithConfigFile() public void CanInitializeWithConfigFileAndConfigurationFileCache() { Configuration configuration = new NHibernateSessionFactoryBuilder() - .UseConfigurationCache(new NHibernateConfigurationFileCache("default", _tempFileName)) - .WithFileDependency("SharpArch.NHibernate") .UseConfigFile(GetConfigFullName()) .BuildConfiguration(); @@ -109,7 +104,6 @@ public void CanInitializeWithPersistenceConfigurerAndNoConfigFile() SQLiteConfiguration.Standard.ConnectionString(c => c.Is("Data Source=:memory:;Version=3;New=True;")); Configuration configuration = new NHibernateSessionFactoryBuilder() - .WithFileDependency("SharpArch.NHibernate") .UsePersistenceConfigurer(persistenceConfigurer) .BuildConfiguration(); @@ -117,39 +111,6 @@ public void CanInitializeWithPersistenceConfigurerAndNoConfigFile() configuration.BuildSessionFactory(); } - [Test] - public void DoesInitializeFailWhenCachingFileDependencyCannotBeFound() - { - Assert.Throws( - () => { - new NHibernateSessionFactoryBuilder() - // Random Guid value as dependency file to cause the exception - .UseConfigurationCache(new NHibernateConfigurationFileCache("default", _tempFileName)) - .WithFileDependency(Guid.NewGuid().ToString("D")) - .UseConfigFile(GetConfigFullName()) - .BuildConfiguration(); - }); - } - - [Test] - public void ShouldPersistExposedConfigurationChanges() - { - var cache = new InMemoryCache("default"); - - new NHibernateSessionFactoryBuilder() - .UseConfigFile(GetConfigFullName()) - .ExposeConfiguration(c => c.SetProperty("connection.connection_string", "updated-connection")) - .UseConfigurationCache(cache) - .BuildConfiguration(); - - Configuration config = new NHibernateSessionFactoryBuilder() - .UseConfigFile(GetConfigFullName()) - .UseConfigurationCache(cache) - .BuildConfiguration(); - - config.Properties["connection.connection_string"].Should().Be("updated-connection"); - } - [Test] public void WhenUsingDataAnnotationValidators_ShouldKeepRegisteredPreInsertEventListeners() { @@ -172,30 +133,4 @@ public void WhenUsingDataAnnotationValidators_ShouldKeepRegisteredPreUpdateEvent configuration.EventListeners.PreUpdateEventListeners.Should().Contain(l => l is PreUpdateListener); } } - - - class InMemoryCache : NHibernateConfigurationCacheBase - { - private DateTime? _timestamp; - private byte[] _data; - - /// - public InMemoryCache([NotNull] string sessionName) - : base(sessionName) - { - } - - /// - protected override byte[] GetCachedConfiguration() => _data; - - /// - protected override DateTime? GetCachedTimestampUtc() => _timestamp; - - /// - protected override void SaveConfiguration(byte[] data, DateTime timestampUtc) - { - _data = data; - _timestamp = timestampUtc; - } - } } diff --git a/Src/Tests/SharpArch.XunitTests.NHibernate/NHibernateSessionFactoryBuilderTests.cs b/Src/Tests/SharpArch.XunitTests.NHibernate/NHibernateSessionFactoryBuilderTests.cs deleted file mode 100644 index 0aaf80eff..000000000 --- a/Src/Tests/SharpArch.XunitTests.NHibernate/NHibernateSessionFactoryBuilderTests.cs +++ /dev/null @@ -1,212 +0,0 @@ -namespace Tests.SharpArch.NHibernate -{ - using System; - using System.IO; - using System.Reflection; - using FluentAssertions; - using FluentNHibernate.Cfg.Db; - using global::NHibernate.Cfg; - using global::SharpArch.Infrastructure.Caching; - using global::SharpArch.NHibernate; - using JetBrains.Annotations; - using Xunit; - - - public class NHibernateSessionFactoryBuilderTests : IDisposable - { - readonly string _tempFileName; - DependencyList _dependencyList; - - /// - public NHibernateSessionFactoryBuilderTests() - { - _tempFileName = "SharpArch.Tests." + Guid.NewGuid().ToString("D") + ".tmp"; - _dependencyList = DependencyList.WithBasePathOfAssembly(Assembly.GetExecutingAssembly()); - } - - /// - public void Dispose() - { - try - { - if (File.Exists(_tempFileName)) File.Delete(_tempFileName); - } - // ReSharper disable once CatchAllClause - catch - { - // ignored - } - } - - string GetConfigFullName() - { - const string defaultConfigFile = "sqlite-nhibernate-config.xml"; - return Path.Combine(DependencyList.GetAssemblyCodeBasePath(Assembly.GetExecutingAssembly()), defaultConfigFile); - } - - [Fact] - public void CanConfigureCache() - { - var configureCacheCalled = false; - Action configureCache = c => { configureCacheCalled = true; }; - - new NHibernateSessionFactoryBuilder() - .UseConfigFile(GetConfigFullName()) - .UseCache(configureCache) - .BuildConfiguration(); - - configureCacheCalled.Should().BeTrue(); - } - - [Fact] - public void CanExposeConfiguration() - { - var exposeCalled = false; - Action configure = c => { exposeCalled = true; }; - - new NHibernateSessionFactoryBuilder() - .UseConfigFile(GetConfigFullName()) - .ExposeConfiguration(configure) - .BuildConfiguration(); - - exposeCalled.Should().BeTrue(); - } - - [Fact] - public void CanInitializeWithConfigFile() - { - Configuration configuration = new NHibernateSessionFactoryBuilder() - .UseConfigFile(GetConfigFullName()) - .BuildConfiguration(); - - configuration.Should().NotBeNull(); - - configuration.BuildSessionFactory(); - } - - [Fact] - public void CanInitializeWithConfigFileAndConfigurationFileCache() - { - Configuration configuration = new NHibernateSessionFactoryBuilder() - .UseConfigurationCache(new NHibernateConfigurationFileCache("default", "NHibernateFactoryBuilderTests.bin")) - .UseConfigFile(GetConfigFullName()) - .BuildConfiguration(); - - configuration.Should().NotBeNull(); - - configuration.BuildSessionFactory(); - } - - [Fact] - public void CanInitializeWithPersistenceConfigurerAndConfigFile() - { - SQLiteConfiguration persistenceConfigurer = - SQLiteConfiguration.Standard.ConnectionString(c => c.Is("Data Source=:memory:;Version=3;New=True;")); - - Configuration configuration = new NHibernateSessionFactoryBuilder() - .UsePersistenceConfigurer(persistenceConfigurer) - .UseConfigFile(GetConfigFullName()) - .BuildConfiguration(); - - configuration.BuildSessionFactory(); - } - - [Fact] - public void CanInitializeWithPersistenceConfigurerAndNoConfigFile() - { - SQLiteConfiguration persistenceConfigurer = - SQLiteConfiguration.Standard.ConnectionString(c => c.Is("Data Source=:memory:;Version=3;New=True;")); - - Configuration configuration = new NHibernateSessionFactoryBuilder() - .WithFileDependency("SharpArch.NHibernate") - .UsePersistenceConfigurer(persistenceConfigurer) - .BuildConfiguration(); - - configuration.BuildSessionFactory(); - } - - [Fact] - public void DoesInitializeFailWhenCachingFileDependencyCannotBeFound() - { - Assert.Throws( - () => - { - new NHibernateSessionFactoryBuilder() - // Random Guid value as dependency file to cause the exception - .UseConfigurationCache(new NHibernateConfigurationFileCache("default", _tempFileName)) - .UseConfigFile(GetConfigFullName()) - .WithFileDependency(Guid.NewGuid().ToString("D")) - .BuildConfiguration(); - }); - } - - [Fact] - public void ShouldPersistExposedConfigurationChanges() - { - var cache = new InMemoryCache("default"); - - new NHibernateSessionFactoryBuilder() - .UseConfigFile(GetConfigFullName()) - .ExposeConfiguration(c => c.SetProperty("connection.connection_string", "updated-connection")) - .UseConfigurationCache(cache) - .BuildConfiguration(); - - Configuration config = new NHibernateSessionFactoryBuilder() - .UseConfigFile(GetConfigFullName()) - .UseConfigurationCache(cache) - .BuildConfiguration(); - - config.Properties["connection.connection_string"].Should().Be("updated-connection"); - } - - [Fact] - public void WhenUsingDataAnnotationValidators_ShouldKeepRegisteredPreInsertEventListeners() - { - Configuration configuration = new NHibernateSessionFactoryBuilder() - .UseConfigFile(GetConfigFullName()) - .UseDataAnnotationValidators(true) - .BuildConfiguration(); - - configuration.EventListeners.PreInsertEventListeners.Should().Contain(l => l is PreInsertListener); - } - - [Fact] - public void WhenUsingDataAnnotationValidators_ShouldKeepRegisteredPreUpdateEventListeners() - { - Configuration configuration = new NHibernateSessionFactoryBuilder() - .UseConfigFile(GetConfigFullName()) - .UseDataAnnotationValidators(true) - .BuildConfiguration(); - - configuration.EventListeners.PreUpdateEventListeners.Should().Contain(l => l is PreUpdateListener); - } - } - - - class InMemoryCache : NHibernateConfigurationCacheBase - { - byte[] _data; - DateTime? _timestamp; - - /// - public InMemoryCache([NotNull] string sessionName) - : base(sessionName) - { - } - - /// - protected override byte[] GetCachedConfiguration() - => _data; - - /// - protected override DateTime? GetCachedTimestampUtc() - => _timestamp; - - /// - protected override void SaveConfiguration(byte[] data, DateTime timestampUtc) - { - _data = data; - _timestamp = timestampUtc; - } - } -} diff --git a/Src/Tests/SharpArch.XunitTests/SharpArch.Infrastructure/DependencyListTests.cs b/Src/Tests/SharpArch.XunitTests/SharpArch.Infrastructure/DependencyListTests.cs deleted file mode 100644 index 14c434e6e..000000000 --- a/Src/Tests/SharpArch.XunitTests/SharpArch.Infrastructure/DependencyListTests.cs +++ /dev/null @@ -1,95 +0,0 @@ -namespace Tests.SharpArch.Infrastructure -{ - using System; - using System.IO; - using FluentAssertions; - using global::SharpArch.Infrastructure.Abstractions; - using global::SharpArch.Infrastructure.Caching; - using Moq; - using Xunit; - - - public class DependencyListTests - { - private const string BasePath = "d:\\"; - private readonly Mock _fileSystemMock; - private readonly DependencyList _dependencyList; - - /// - public DependencyListTests() - { - _fileSystemMock = new Mock(); - _dependencyList = new DependencyList(_fileSystemMock.Object, BasePath); - } - - [Fact] - public void AddFile_NonExistingFile_Should_Throw_FileNotFoundException() - { - const string fileName = "e:\\path\\file.txt"; - _fileSystemMock.Setup(f => f.FileExists(It.IsAny())).Returns(false); - - Action addFile = () => _dependencyList.AddFile(fileName); - addFile.Should().Throw(); - } - - [Fact] - public void AddFile_WithAbsolutePath_Should_AddFile_AsIs() - { - const string fileName = "e:\\path\\file.txt"; - _fileSystemMock.Setup(f => f.FileExists(fileName)).Returns(true); - - _dependencyList.AddFiles(new[] {fileName}); - _dependencyList.Build().Should().OnlyContain(x => x == fileName); - } - - [Fact] - public void AddFile_WithRelativePath_Should_Use_BasePath() - { - const string fileName = "file.txt"; - const string fileWithBasePath = BasePath + fileName; - _fileSystemMock.Setup(f => f.FileExists(fileWithBasePath)).Returns(true); - - _dependencyList.AddFile(fileName); - _dependencyList.Build() - .Should().OnlyContain(x => x == fileWithBasePath); - } - - [Fact] - public void AddFile_Should_Try_FileName_With_DllExtensionAdded() - { - const string fileName = "file"; - const string fileWithDllExt = "file.dll"; - _fileSystemMock.Setup(f => f.FileExists(fileWithDllExt)).Returns(true); - - _dependencyList.AddFile(fileName); - _dependencyList.Build() - .Should().OnlyContain(x => x == fileWithDllExt); - } - - [Fact] - public void AddFile_Should_Try_FileName_With_BasePath_And_DllExtensionAdded() - { - const string fileName = "file"; - const string fullPath = BasePath + "file.dll"; - _fileSystemMock.Setup(f => f.FileExists(fullPath)).Returns(true); - - _dependencyList.AddFile(fileName); - _dependencyList.Build() - .Should().OnlyContain(x => x == fullPath); - } - - [Fact] - public void Can_Calculate_Maximum_ModificationDate() - { - const string fileName1 = "file1"; - const string fileName2 = "file2"; - - _fileSystemMock.Setup(f => f.FileExists(It.IsAny())).Returns(true); - _fileSystemMock.Setup(f => f.GetLastWriteTimeUtc(BasePath + fileName1)).Returns(new DateTime(2018, 01, 01, 00, 00, 00, DateTimeKind.Utc)); - _fileSystemMock.Setup(f => f.GetLastWriteTimeUtc(BasePath + fileName2)).Returns(new DateTime(2019, 01, 01, 00, 00, 00, DateTimeKind.Utc)); - - _dependencyList.AddFiles(new[] {fileName1, fileName2}); - _dependencyList.GetLastModificationTime().Should().Be(new DateTime(2019, 01, 01, 00, 00, 00, DateTimeKind.Utc)); - } - } -} diff --git a/Src/Tests/SharpArch.XunitTests/SharpArch.Infrastructure/DependencyListTests_RealFileSystem.cs b/Src/Tests/SharpArch.XunitTests/SharpArch.Infrastructure/DependencyListTests_RealFileSystem.cs deleted file mode 100644 index 670fa1067..000000000 --- a/Src/Tests/SharpArch.XunitTests/SharpArch.Infrastructure/DependencyListTests_RealFileSystem.cs +++ /dev/null @@ -1,59 +0,0 @@ -namespace Tests.SharpArch.Infrastructure -{ - using System.IO; - using System.Reflection; - using FluentAssertions; - using global::SharpArch.Infrastructure.Caching; - using Xunit; - - - public class DependencyList_With_RealFileSystem_Tests - { - private readonly DependencyList _dependencyList; - - /// - public DependencyList_With_RealFileSystem_Tests() - { - _dependencyList = DependencyList.WithBasePathOfAssembly(Assembly.GetExecutingAssembly()); - } - - [Fact] - public void Should_Resolve_AssemblyName() - { - var list = _dependencyList.AddAssemblyOf().Build(); - list.Should().HaveCount(1); - var fullPath = list[0]; - fullPath.Should().EndWith("SharpArch.XunitTests.dll"); - File.Exists(fullPath).Should().BeTrue("file '{0}'cannot be found on disk", fullPath); - } - - [Fact] - public void Should_Resolve_Assembly_By_Name() - { - var list = _dependencyList.AddFile("SharpArch.Domain").Build(); - list.Should().HaveCount(1); - var fullPath = list[0]; - fullPath.Should().EndWith("SharpArch.Domain.dll"); - File.Exists(fullPath).Should().BeTrue("file '{0}'cannot be found on disk", fullPath); - } - - [Fact] - public void Should_Resolve_Assembly_By_NameAndExtension() - { - var list = _dependencyList.AddFile("SharpArch.Domain.dll").Build(); - list.Should().HaveCount(1); - var fullPath = list[0]; - fullPath.Should().EndWith("SharpArch.Domain.dll"); - File.Exists(fullPath).Should().BeTrue("file '{0}'cannot be found on disk", fullPath); - } - - [Fact] - public void Can_Get_LastModificationTime() - { - _dependencyList - .AddAssemblyOf() - .AddAssemblyOf(); - _dependencyList.GetLastModificationTime().Should().NotBeNull(); - } - } -} From 2839329bce9a2b82f57cd9512906e781023dfeb7 Mon Sep 17 00:00:00 2001 From: vk Date: Mon, 18 Jan 2021 16:29:27 -0500 Subject: [PATCH 04/13] Remove NHibernate configuration cache, closes #228 --- .../SharpArch.Infrastructure.csproj | 4 ---- .../NHibernateSessionFactoryBuilder.cs | 13 +------------ 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/Src/SharpArch.Infrastructure/SharpArch.Infrastructure.csproj b/Src/SharpArch.Infrastructure/SharpArch.Infrastructure.csproj index fac7392f0..d83e240c2 100644 --- a/Src/SharpArch.Infrastructure/SharpArch.Infrastructure.csproj +++ b/Src/SharpArch.Infrastructure/SharpArch.Infrastructure.csproj @@ -32,9 +32,5 @@ - - - - diff --git a/Src/SharpArch.NHibernate/NHibernateSessionFactoryBuilder.cs b/Src/SharpArch.NHibernate/NHibernateSessionFactoryBuilder.cs index 72ccedab3..da4ae0ade 100644 --- a/Src/SharpArch.NHibernate/NHibernateSessionFactoryBuilder.cs +++ b/Src/SharpArch.NHibernate/NHibernateSessionFactoryBuilder.cs @@ -31,10 +31,9 @@ public class NHibernateSessionFactoryBuilder /// /// Default NHibernate session factory key. /// - public static readonly string DefaultConfigurationName = "nhibernate.current_session"; + [NotNull] public static readonly string DefaultConfigurationName = "nhibernate.current_session"; readonly List _mappingAssemblies; - List _additionalDependencies; AutoPersistenceModel _autoPersistenceModel; string _configFile; @@ -67,16 +66,6 @@ public ISessionFactory BuildSessionFactory() /// /// Builds NHibernate configuration. /// - /// - /// - /// Any changes made to configuration object after this point will not be persisted in configuration cache. - /// This can be useful to make dynamic changes to configuration or in case changes cannot be serialized - /// (e.g. event listeners are not marked with . - /// - /// - /// To make persistent changes use . - /// - /// /// No dependencies were specified [NotNull] public Configuration BuildConfiguration() From 2eeae0f047b294c00859fdadc32987464fca1e32 Mon Sep 17 00:00:00 2001 From: vk Date: Mon, 18 Jan 2021 21:34:33 -0500 Subject: [PATCH 05/13] Add async support for xUnit fixture, closes #226 --- Directory.Build.props | 2 +- .../Model/ChildTests.cs | 15 ++--- .../Model/MessageTests.cs | 9 +-- .../Model/ParentTests.cs | 10 ++-- .../Model/PaymentSchedulingQueryTests.cs | 27 +++++---- .../Model/UserTests.cs | 16 ++--- Src/Common/NHibernate/TestDatabaseSetup.cs | 58 +++++++++---------- .../NHibernateRepository.cs | 27 --------- .../NHibernateRepositoryBase.cs | 33 +++++------ .../TransientDatabaseTests.cs | 47 ++++++++++----- .../HasUniqueDomainSignatureValidatorTests.cs | 19 +++--- .../NHibernateRepositoryTests.cs | 8 +-- 12 files changed, 129 insertions(+), 142 deletions(-) delete mode 100644 Src/SharpArch.NHibernate/NHibernateRepository.cs diff --git a/Directory.Build.props b/Directory.Build.props index e448b358e..5007d5aaf 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -14,7 +14,7 @@ false - + netcoreapp2.1;netcoreapp3.1;net5 diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/ChildTests.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/ChildTests.cs index 8a11b2cce..d3adb010e 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/ChildTests.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/ChildTests.cs @@ -1,6 +1,7 @@ namespace Suteki.TardisBank.Tests.Model { using System; + using System.Threading; using System.Threading.Tasks; using Domain; using FluentAssertions; @@ -23,17 +24,17 @@ public ChildTests(TransientDatabaseSetup dbSetup) _childRepository = new LinqRepository(TransactionManager); } - protected override void LoadTestData() + protected override async Task LoadTestData(CancellationToken cancellationToken) { var parent = new Parent("Mike Hadlow", "mike@yahoo.com", "yyy"); - Session.Save(parent); + await Session.SaveAsync(parent, cancellationToken); _parentId = parent.Id; var child = parent.CreateChild("Leo", "leohadlow", "xxx"); - Session.Save(child); - FlushSessionAndEvict(child); - FlushSessionAndEvict(parent); + await Session.SaveAsync(child, cancellationToken); + await FlushSessionAndEvict(child, cancellationToken); + await FlushSessionAndEvict(parent, cancellationToken); _childId = child.Id; } @@ -44,7 +45,7 @@ public async Task Should_be_able_to_add_schedule_to_account() childToTestOn.Should().NotBeNull(); childToTestOn.Account.AddPaymentSchedule(DateTime.UtcNow, Interval.Week, 10, "Weekly pocket money"); - FlushSessionAndEvict(childToTestOn); + await FlushSessionAndEvict(childToTestOn); var child = await _childRepository.GetAsync(_childId); child.Should().NotBeNull(); @@ -56,7 +57,7 @@ public async Task Should_be_able_to_add_transaction_to_account() { var childToTestOn = await _childRepository.GetAsync(_childId); childToTestOn.ReceivePayment(10, "Reward"); - FlushSessionAndEvict(childToTestOn); + await FlushSessionAndEvict(childToTestOn); var child = await _childRepository.GetAsync(_childId); child.Account.Transactions[0].Id.Should().BePositive(); diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/MessageTests.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/MessageTests.cs index 749755485..2f612ae20 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/MessageTests.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/MessageTests.cs @@ -1,5 +1,6 @@ namespace Suteki.TardisBank.Tests.Model { + using System.Threading; using System.Threading.Tasks; using Domain; using FluentAssertions; @@ -22,12 +23,12 @@ public MessageTests(TransientDatabaseSetup dbSetup) : base(dbSetup) _mediator = new Mock(); } - protected override void LoadTestData() + protected override async Task LoadTestData(CancellationToken cancellationToken) { User user = new Parent("Dad", "mike@mike.com", "xxx"); - Session.Save(user); + await Session.SaveAsync(user, cancellationToken); - FlushSessionAndEvict(user); + await FlushSessionAndEvict(user, cancellationToken); _userId = user.Id; } @@ -39,7 +40,7 @@ public async Task Should_be_able_to_add_a_message_to_a_user() userToTestWith.SendMessage("some message", _mediator.Object); - FlushSessionAndEvict(userToTestWith); + await FlushSessionAndEvict(userToTestWith); Parent parent = await parentRepository.GetAsync(_userId); parent.Messages.Count.Should().Be(1); diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/ParentTests.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/ParentTests.cs index a69f4a1fe..2b24cff90 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/ParentTests.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/ParentTests.cs @@ -1,9 +1,9 @@ namespace Suteki.TardisBank.Tests.Model { + using System.Threading; using System.Threading.Tasks; using Domain; using FluentAssertions; - using SharpArch.NHibernate; using SharpArch.NHibernate.Impl; using SharpArch.Testing.Xunit.NHibernate; using Xunit; @@ -18,11 +18,11 @@ public ParentTests(TransientDatabaseSetup dbSetup) { } - protected override void LoadTestData() + protected override async Task LoadTestData(CancellationToken cancellationToken) { var parent = new Parent("Mike Hadlow", string.Format("{0}@yahoo.com", "mike"), "yyy"); - Session.Save(parent); - FlushSessionAndEvict(parent); + await Session.SaveAsync(parent, cancellationToken); + await FlushSessionAndEvict(parent, cancellationToken); _parentId = parent.Id; } @@ -36,7 +36,7 @@ public async Task Should_be_able_to_add_a_child_to_a_parent() savedParent.CreateChild("jim", "jim123", "passw0rd1"); savedParent.CreateChild("jenny", "jenny123", "passw0rd2"); savedParent.CreateChild("jez", "jez123", "passw0rd3"); - FlushSessionAndEvict(savedParent); + await FlushSessionAndEvict(savedParent); Parent parent = await linqRepository.GetAsync(_parentId); parent.Children.Count.Should().Be(3); diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/PaymentSchedulingQueryTests.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/PaymentSchedulingQueryTests.cs index de77e352a..ab7820ea6 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/PaymentSchedulingQueryTests.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/PaymentSchedulingQueryTests.cs @@ -3,8 +3,11 @@ namespace Suteki.TardisBank.Tests.Model using System; using System.Collections.Generic; using System.Linq; + using System.Threading; + using System.Threading.Tasks; using Domain; using FluentAssertions; + using NHibernate.Linq; using SharpArch.Testing.Xunit.NHibernate; using Tasks; using Xunit; @@ -21,17 +24,17 @@ public PaymentSchedulingQueryTests(TransientDatabaseSetup dbSetup) { } - protected override void LoadTestData() + protected override async Task LoadTestData(CancellationToken cancellationToken) { _parent = new Parent("parent", "parent", "xxx"); - Session.Save(_parent); + await Session.SaveAsync(_parent, cancellationToken); _someDate = new DateTime(2010, 4, 5); - Session.Save(CreateChildWithSchedule("one", 1M, _someDate.AddDays(-2))); - Session.Save(CreateChildWithSchedule("two", 2M, _someDate.AddDays(-1))); - Session.Save(CreateChildWithSchedule("three", 3M, _someDate)); - Session.Save(CreateChildWithSchedule("four", 4M, _someDate.AddDays(1))); - Session.Save(CreateChildWithSchedule("five", 5M, _someDate.AddDays(2))); - Session.Flush(); + await Session.SaveAsync(CreateChildWithSchedule("one", 1M, _someDate.AddDays(-2)), cancellationToken).ConfigureAwait(false); + await Session.SaveAsync(CreateChildWithSchedule("two", 2M, _someDate.AddDays(-1)), cancellationToken).ConfigureAwait(false); + await Session.SaveAsync(CreateChildWithSchedule("three", 3M, _someDate), cancellationToken).ConfigureAwait(false); + await Session.SaveAsync(CreateChildWithSchedule("four", 4M, _someDate.AddDays(1)), cancellationToken).ConfigureAwait(false); + await Session.SaveAsync(CreateChildWithSchedule("five", 5M, _someDate.AddDays(2)), cancellationToken).ConfigureAwait(false); + await Session.FlushAsync(cancellationToken).ConfigureAwait(false); } Child CreateChildWithSchedule(string name, decimal amount, DateTime startDate) @@ -42,17 +45,17 @@ Child CreateChildWithSchedule(string name, decimal amount, DateTime startDate) } [Fact] - public void Should_be_able_to_query_all_pending_scheduled_payments() + public async Task Should_be_able_to_query_all_pending_scheduled_payments() { ISchedulerService schedulerService = new SchedulerService(Session); schedulerService.ExecuteUpdates(_someDate); - Session.Flush(); + await Session.FlushAsync(); // check results - List results = Session.Query().ToList(); + List results = await Session.Query().ToListAsync(); - results.Count().Should().Be(5); + results.Should().HaveCount(5); results.Single(x => x.Name == "one").Account.PaymentSchedules[0].NextRun.Should().Be(_someDate.AddDays(5)); results.Single(x => x.Name == "two").Account.PaymentSchedules[0].NextRun.Should().Be(_someDate.AddDays(6)); diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/UserTests.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/UserTests.cs index bbb172257..01bf72407 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/UserTests.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/UserTests.cs @@ -1,6 +1,8 @@ namespace Suteki.TardisBank.Tests.Model { using System.Linq; + using System.Threading; + using System.Threading.Tasks; using Domain; using FluentAssertions; using SharpArch.Testing.Xunit.NHibernate; @@ -14,23 +16,23 @@ public UserTests(TransientDatabaseSetup dbSetup) { } - protected override void LoadTestData() + protected override async Task LoadTestData(CancellationToken cancellationToken) { var mike = new Parent("Mike Hadlow", "mike@yahoo.com", "yyy"); - Session.Save(mike); + await Session.SaveAsync(mike, cancellationToken); Child leo = mike.CreateChild("Leo", "leohadlow", "xxx"); Child yuna = mike.CreateChild("Yuna", "yunahadlow", "xxx"); - Session.Save(leo); - Session.Save(yuna); + await Session.SaveAsync(leo, cancellationToken); + await Session.SaveAsync(yuna, cancellationToken); var john = new Parent("John Robinson", "john@gmail.com", "yyy"); - Session.Save(john); + await Session.SaveAsync(john, cancellationToken); Child jim = john.CreateChild("Jim", "jimrobinson", "xxx"); - Session.Save(jim); + await Session.SaveAsync(jim, cancellationToken); - Session.Flush(); + await Session.FlushAsync(cancellationToken).ConfigureAwait(false); } [Fact] diff --git a/Src/Common/NHibernate/TestDatabaseSetup.cs b/Src/Common/NHibernate/TestDatabaseSetup.cs index 9a0b2b0d2..4dd57282f 100644 --- a/Src/Common/NHibernate/TestDatabaseSetup.cs +++ b/Src/Common/NHibernate/TestDatabaseSetup.cs @@ -5,6 +5,8 @@ using System.IO; using System.Linq; using System.Reflection; + using System.Threading; + using System.Threading.Tasks; using FluentNHibernate.Automapping; using global::NHibernate; using global::NHibernate.Cfg; @@ -194,9 +196,7 @@ public ISession InitializeSession() /// /// The session. public static void Close([CanBeNull] ISession session) - { - session?.Dispose(); - } + => session?.Dispose(); /// /// Shutdowns the specified session factory. @@ -206,32 +206,30 @@ public static void Close([CanBeNull] ISession session) /// Dispose will destroy Session Factory associated with this instance. /// public static void Shutdown([CanBeNull] ISessionFactory sessionFactory) - { - sessionFactory?.Dispose(); - } - - /// - /// Loads the assembly. - /// - /// - /// - [NotNull] - static Assembly TryLoadAssembly([NotNull] string assemblyPath) - => Assembly.LoadFrom(assemblyPath); - - /// - /// Adds dll extension to assembly name if required. - /// - /// Name of the assembly. - /// - [NotNull] - static string EnsureDllExtension([NotNull] string assemblyName) - { - assemblyName = assemblyName.Trim(); - const string dllExtension = ".dll"; - if (!assemblyName.EndsWith(dllExtension, StringComparison.OrdinalIgnoreCase)) assemblyName = string.Concat(assemblyName, dllExtension); - - return assemblyName; - } + => sessionFactory?.Dispose(); + + ///// + ///// Loads the assembly. + ///// + ///// + ///// + //[NotNull] + //static Assembly TryLoadAssembly([NotNull] string assemblyPath) + // => Assembly.LoadFrom(assemblyPath); + + ///// + ///// Adds dll extension to assembly name if required. + ///// + ///// Name of the assembly. + ///// + //[NotNull] + //static string EnsureDllExtension([NotNull] string assemblyName) + //{ + // assemblyName = assemblyName.Trim(); + // const string dllExtension = ".dll"; + // if (!assemblyName.EndsWith(dllExtension, StringComparison.OrdinalIgnoreCase)) assemblyName = string.Concat(assemblyName, dllExtension); + + // return assemblyName; + //} } } diff --git a/Src/SharpArch.NHibernate/NHibernateRepository.cs b/Src/SharpArch.NHibernate/NHibernateRepository.cs deleted file mode 100644 index ffefb2598..000000000 --- a/Src/SharpArch.NHibernate/NHibernateRepository.cs +++ /dev/null @@ -1,27 +0,0 @@ -using JetBrains.Annotations; - -namespace SharpArch.NHibernate.Impl -{ - using System; - using Domain.DomainModel; - - - /// - /// NHibernate repository implementation. - /// - /// - /// This implementation should be used in simplified, single-database model. - /// - /// Entity type/ - /// Entity identifier type. - [PublicAPI] - public class NHibernateRepository : NHibernateRepositoryBase - where TEntity : class, IEntity - where TId : IEquatable - { - /// - public NHibernateRepository([NotNull] INHibernateTransactionManager transactionManager) : base(transactionManager) - { - } - } -} diff --git a/Src/SharpArch.NHibernate/NHibernateRepositoryBase.cs b/Src/SharpArch.NHibernate/NHibernateRepositoryBase.cs index f98610eef..4abd2f8c9 100644 --- a/Src/SharpArch.NHibernate/NHibernateRepositoryBase.cs +++ b/Src/SharpArch.NHibernate/NHibernateRepositoryBase.cs @@ -10,31 +10,23 @@ namespace SharpArch.NHibernate using Domain.PersistenceSupport; using global::NHibernate; using global::NHibernate.Criterion; - using Impl; using JetBrains.Annotations; /// - /// Provides a fully loaded DAO which may be created in a few ways including: - /// * Direct instantiation; e.g., new GenericDao<Customer, string> - /// * Spring configuration; e.g., - /// + /// Provides a fully loaded DAO. /// - /// - /// Keep constructor protected to enable support of single-database () - /// and multiple-database - /// - /// Entity type/ + /// Entity type. /// Entity identifier type. [PublicAPI] - public class NHibernateRepositoryBase : INHibernateRepository + public class NHibernateRepository : INHibernateRepository where TEntity : class, IEntity where TId : IEquatable { /// /// Gets NHibernate session. /// + [NotNull] protected ISession Session => TransactionManager.Session; /// @@ -42,14 +34,15 @@ public class NHibernateRepositoryBase : INHibernateRepository + [NotNull] protected INHibernateTransactionManager TransactionManager { get; } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The transaction manager. /// - protected NHibernateRepositoryBase( + public NHibernateRepository( [NotNull] INHibernateTransactionManager transactionManager) { TransactionManager = transactionManager ?? throw new ArgumentNullException(nameof(transactionManager)); @@ -180,11 +173,11 @@ public virtual async Task UpdateAsync(TEntity entity, CancellationToken } /// - /// Translates a domain layer lock mode into an NHibernate lock mode via reflection. This is - /// provided to facilitate developing the domain layer without a direct dependency on the + /// Translates a domain layer lock mode into an NHibernate lock mode via reflection. + /// This is provided to facilitate developing the domain layer without a direct dependency on the /// NHibernate assembly. /// - static LockMode ConvertFrom(Enums.LockMode lockMode) + [NotNull] static LockMode ConvertFrom(Enums.LockMode lockMode) => lockMode switch { Enums.LockMode.None => LockMode.None, @@ -193,9 +186,9 @@ static LockMode ConvertFrom(Enums.LockMode lockMode) Enums.LockMode.UpgradeNoWait => LockMode.UpgradeNoWait, Enums.LockMode.Write => LockMode.Write, _ => throw new ArgumentOutOfRangeException(nameof(lockMode), lockMode, - "The provided lock mode , '" + lockMode + "', could not be translated into an NHibernate.LockMode. " + - "This is probably because NHibernate was updated and now has different lock modes which are out of synch " + - "with the lock modes maintained in the domain layer.") + $"The provided lock mode , '{lockMode}', could not be translated into an NHibernate.LockMode. " + + "This is probably because NHibernate was updated and now has different lock modes " + + "which are out of synch with the lock modes maintained in the domain layer.") }; } } diff --git a/Src/SharpArch.Testing.Xunit.NHibernate/TransientDatabaseTests.cs b/Src/SharpArch.Testing.Xunit.NHibernate/TransientDatabaseTests.cs index de96d9358..b8d156403 100644 --- a/Src/SharpArch.Testing.Xunit.NHibernate/TransientDatabaseTests.cs +++ b/Src/SharpArch.Testing.Xunit.NHibernate/TransientDatabaseTests.cs @@ -1,12 +1,14 @@ namespace SharpArch.Testing.Xunit.NHibernate { using System; + using System.Threading; + using System.Threading.Tasks; using global::NHibernate; using global::Xunit; using JetBrains.Annotations; using SharpArch.NHibernate; using SharpArch.NHibernate.Impl; - using SharpArch.Testing.NHibernate; + using Testing.NHibernate; /// @@ -21,33 +23,45 @@ /// /// [PublicAPI] - public abstract class TransientDatabaseTests : IClassFixture, IDisposable + public abstract class TransientDatabaseTests : IClassFixture, IDisposable, IAsyncLifetime where TDatabaseSetup : TestDatabaseSetup, new() { /// /// Transaction manager. /// + [NotNull] protected TransactionManager TransactionManager { get; private set; } /// /// Database initializer. /// + [NotNull] protected TestDatabaseSetup DbSetup { get; private set; } /// /// Database session. /// + [NotNull] protected ISession Session => TransactionManager.Session; - /// - protected TransientDatabaseTests(TestDatabaseSetup dbSetup) + /// + /// Constructor. + /// + /// + protected TransientDatabaseTests([NotNull] TestDatabaseSetup dbSetup) { - DbSetup = dbSetup; + DbSetup = dbSetup ?? throw new ArgumentNullException(nameof(dbSetup)); TransactionManager = new TransactionManager(DbSetup.InitializeSession()); - // ReSharper disable once VirtualMemberCallInConstructor - LoadTestData(); } + /// + public Task InitializeAsync() + => LoadTestData(CancellationToken.None); + + /// + public Task DisposeAsync() + => Task.CompletedTask; + /// public virtual void Dispose() { @@ -58,28 +72,29 @@ public virtual void Dispose() /// Flushes the session and evicts entity from it. /// /// The entity instance. + /// Cancellation token. /// is - protected void FlushSessionAndEvict([NotNull] object instance) - { - if (instance == null) throw new ArgumentNullException(nameof(instance)); - Session.FlushAndEvict(instance); - } + [NotNull] + protected Task FlushSessionAndEvict([NotNull] object instance, CancellationToken cancellationToken = default) + => Session.FlushAndEvictAsync(instance, cancellationToken); /// /// Saves entity then flushes sessions and evicts it. /// /// The entity instance. + /// Cancellation token. /// is - protected void SaveAndEvict([NotNull] object instance) + protected async Task SaveAndEvict([NotNull] object instance, CancellationToken cancellationToken = default) { if (instance == null) throw new ArgumentNullException(nameof(instance)); - Session.Save(instance); - FlushSessionAndEvict(instance); + await Session.SaveAsync(instance, cancellationToken).ConfigureAwait(false); + await FlushSessionAndEvict(instance, cancellationToken).ConfigureAwait(false); } /// /// Initializes database before each test run. /// - protected abstract void LoadTestData(); + [NotNull] + protected abstract Task LoadTestData(CancellationToken cancellationToken); } } diff --git a/Src/Tests/SharpArch.XunitTests.NHibernate/HasUniqueDomainSignatureValidatorTests.cs b/Src/Tests/SharpArch.XunitTests.NHibernate/HasUniqueDomainSignatureValidatorTests.cs index a12e27972..146df4abd 100644 --- a/Src/Tests/SharpArch.XunitTests.NHibernate/HasUniqueDomainSignatureValidatorTests.cs +++ b/Src/Tests/SharpArch.XunitTests.NHibernate/HasUniqueDomainSignatureValidatorTests.cs @@ -1,5 +1,7 @@ namespace Tests.SharpArch.NHibernate { + using System.Threading; + using System.Threading.Tasks; using Domain; using FluentAssertions; using Xunit; @@ -8,15 +10,14 @@ public class HasUniqueDomainSignatureValidatorTests : HasUniqueDomainSignatureTestsBase { /// - protected override void LoadTestData() - { - } + protected override Task LoadTestData(CancellationToken cancellationToken) + => Task.CompletedTask; [Fact] - public void WhenEntityWithDuplicateGuidExists_Should_MarkEntityAsInvalid() + public async Task WhenEntityWithDuplicateGuidExists_Should_MarkEntityAsInvalid() { var objectWithGuidId = new ObjectWithGuidId {Name = "codai"}; - SaveAndEvict(objectWithGuidId); + await SaveAndEvict(objectWithGuidId, CancellationToken.None); var duplicateObjectWithGuidId = new ObjectWithGuidId {Name = "codai"}; duplicateObjectWithGuidId.IsValid(ValidationContextFor(duplicateObjectWithGuidId)) @@ -24,20 +25,20 @@ public void WhenEntityWithDuplicateGuidExists_Should_MarkEntityAsInvalid() } [Fact] - public void WhenEntityWithDuplicateIntIdExists_Should_MarkEntityAsInvalid() + public async Task WhenEntityWithDuplicateIntIdExists_Should_MarkEntityAsInvalid() { var contractor = new Contractor {Name = "codai"}; - SaveAndEvict(contractor); + await SaveAndEvict(contractor, CancellationToken.None); var duplicateContractor = new Contractor {Name = "codai"}; duplicateContractor.IsValid(ValidationContextFor(duplicateContractor)) .Should().BeFalse(); } [Fact] - public void WhenEntityWithDuplicateStringIdExists_Should_MarkEntityAsInvalid() + public async Task WhenEntityWithDuplicateStringIdExists_Should_MarkEntityAsInvalid() { var user = new User("user1", "123-12-1234"); - SaveAndEvict(user); + await SaveAndEvict(user, CancellationToken.None); var duplicateUser = new User("user2", "123-12-1234"); duplicateUser.IsValid(ValidationContextFor(duplicateUser)) diff --git a/Src/Tests/SharpArch.XunitTests.NHibernate/NHibernateRepositoryTests.cs b/Src/Tests/SharpArch.XunitTests.NHibernate/NHibernateRepositoryTests.cs index 087da4db4..99ff6fd01 100644 --- a/Src/Tests/SharpArch.XunitTests.NHibernate/NHibernateRepositoryTests.cs +++ b/Src/Tests/SharpArch.XunitTests.NHibernate/NHibernateRepositoryTests.cs @@ -1,9 +1,10 @@ namespace Tests.SharpArch.NHibernate { + using System.Threading; using System.Threading.Tasks; using Domain; using FluentAssertions; - using global::SharpArch.NHibernate.Impl; + using global::SharpArch.NHibernate; using global::SharpArch.Testing.Xunit.NHibernate; using Xunit; @@ -19,9 +20,8 @@ public NHibernateRepositoryTests(NHibernateTestsSetup setup): base(setup) } /// - protected override void LoadTestData() - { - } + protected override Task LoadTestData(CancellationToken cancellationToken) + => Task.CompletedTask; [Fact] public async Task CanSaveAsync() From e91347c1b2dd9faa8fd4e442dcda2bf6dc454dbf Mon Sep 17 00:00:00 2001 From: vk Date: Mon, 18 Jan 2021 21:47:25 -0500 Subject: [PATCH 06/13] Upgrade dependencies --- .../Suteki.TardisBank.Tests.csproj | 2 +- .../Tests/TransactionAttribute.Tests.csproj | 2 +- Src/SharpArch.RavenDb/SharpArch.RavenDb.csproj | 2 +- .../SharpArch.Testing.NUnit.csproj | 2 +- .../SharpArch.Tests.NHibernate.csproj | 8 ++++---- .../SharpArch.XunitTests.NHibernate.csproj | 6 +++--- .../SharpArch.XunitTests/SharpArch.XunitTests.csproj | 4 ++-- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Suteki.TardisBank.Tests.csproj b/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Suteki.TardisBank.Tests.csproj index 7d7abfea4..0dd9f5d6d 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Suteki.TardisBank.Tests.csproj +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Suteki.TardisBank.Tests.csproj @@ -5,7 +5,7 @@ - + diff --git a/Samples/TransactionAttribute/Tests/TransactionAttribute.Tests.csproj b/Samples/TransactionAttribute/Tests/TransactionAttribute.Tests.csproj index 544feaa51..89da09273 100644 --- a/Samples/TransactionAttribute/Tests/TransactionAttribute.Tests.csproj +++ b/Samples/TransactionAttribute/Tests/TransactionAttribute.Tests.csproj @@ -9,7 +9,7 @@ - + all diff --git a/Src/SharpArch.RavenDb/SharpArch.RavenDb.csproj b/Src/SharpArch.RavenDb/SharpArch.RavenDb.csproj index 82fe5ca3d..8a0e5ebd4 100644 --- a/Src/SharpArch.RavenDb/SharpArch.RavenDb.csproj +++ b/Src/SharpArch.RavenDb/SharpArch.RavenDb.csproj @@ -18,7 +18,7 @@ - + diff --git a/Src/SharpArch.Testing.NUnit/SharpArch.Testing.NUnit.csproj b/Src/SharpArch.Testing.NUnit/SharpArch.Testing.NUnit.csproj index d5dd2f81b..d77742781 100644 --- a/Src/SharpArch.Testing.NUnit/SharpArch.Testing.NUnit.csproj +++ b/Src/SharpArch.Testing.NUnit/SharpArch.Testing.NUnit.csproj @@ -20,7 +20,7 @@ - + diff --git a/Src/Tests/SharpArch.Tests.NHibernate/SharpArch.Tests.NHibernate.csproj b/Src/Tests/SharpArch.Tests.NHibernate/SharpArch.Tests.NHibernate.csproj index 513bc71cb..f604b86d4 100644 --- a/Src/Tests/SharpArch.Tests.NHibernate/SharpArch.Tests.NHibernate.csproj +++ b/Src/Tests/SharpArch.Tests.NHibernate/SharpArch.Tests.NHibernate.csproj @@ -12,11 +12,11 @@ - - - + + + - + diff --git a/Src/Tests/SharpArch.XunitTests.NHibernate/SharpArch.XunitTests.NHibernate.csproj b/Src/Tests/SharpArch.XunitTests.NHibernate/SharpArch.XunitTests.NHibernate.csproj index 797145346..ac25e2b89 100644 --- a/Src/Tests/SharpArch.XunitTests.NHibernate/SharpArch.XunitTests.NHibernate.csproj +++ b/Src/Tests/SharpArch.XunitTests.NHibernate/SharpArch.XunitTests.NHibernate.csproj @@ -9,10 +9,10 @@ - - + + - + all diff --git a/Src/Tests/SharpArch.XunitTests/SharpArch.XunitTests.csproj b/Src/Tests/SharpArch.XunitTests/SharpArch.XunitTests.csproj index 10998b8fb..e8060a606 100644 --- a/Src/Tests/SharpArch.XunitTests/SharpArch.XunitTests.csproj +++ b/Src/Tests/SharpArch.XunitTests/SharpArch.XunitTests.csproj @@ -9,8 +9,8 @@ - - + + all From 448c52e5c0a4346f641a3db6b85f64d955b512c7 Mon Sep 17 00:00:00 2001 From: vk Date: Thu, 28 Jan 2021 23:00:28 -0500 Subject: [PATCH 07/13] Switch to MS.Extensions.Logging, closes #237 Add EnabledLogger wrapper --- .../Logging/EnabledLogLevel.cs | 50 ++++++++++++ .../Logging/EnabledLogger.cs | 77 +++++++++++++++++++ .../SharpArch.Infrastructure.csproj | 28 +++---- .../NHibernateRegistrationExtensions.cs | 21 +++-- .../Transaction/AutoTransactionHandler.cs | 36 ++++----- 5 files changed, 171 insertions(+), 41 deletions(-) create mode 100644 Src/SharpArch.Infrastructure/Logging/EnabledLogLevel.cs create mode 100644 Src/SharpArch.Infrastructure/Logging/EnabledLogger.cs diff --git a/Src/SharpArch.Infrastructure/Logging/EnabledLogLevel.cs b/Src/SharpArch.Infrastructure/Logging/EnabledLogLevel.cs new file mode 100644 index 000000000..ceceb1e03 --- /dev/null +++ b/Src/SharpArch.Infrastructure/Logging/EnabledLogLevel.cs @@ -0,0 +1,50 @@ +namespace SharpArch.Infrastructure.Logging +{ + using System; + using JetBrains.Annotations; + using Microsoft.Extensions.Logging; + + + /// + /// Logs with specific log level. + /// + public readonly struct EnabledLogLevel + { + [NotNull] readonly ILogger _logger; + readonly LogLevel _level; + + /// + /// Constructor. + /// + /// Logger. + /// Log level to use. + internal EnabledLogLevel([NotNull] ILogger logger, LogLevel level) + { + _logger = logger; + _level = level; + } + + /// + /// Logs message. + /// + /// Message template. + /// Template parameters. + public void Log([NotNull] string message, [CanBeNull] params object[] args) + { + // ReSharper disable once TemplateIsNotCompileTimeConstantProblem + _logger.Log(_level, message, args); + } + + /// + /// Logs message. + /// + /// Exception to log. + /// Message template. + /// Template parameters. + public void Log([CanBeNull] Exception ex, [NotNull] string message, [CanBeNull] params object[] args) + { + // ReSharper disable once TemplateIsNotCompileTimeConstantProblem + _logger.Log(_level, ex, message, args); + } + } +} diff --git a/Src/SharpArch.Infrastructure/Logging/EnabledLogger.cs b/Src/SharpArch.Infrastructure/Logging/EnabledLogger.cs new file mode 100644 index 000000000..dca75efec --- /dev/null +++ b/Src/SharpArch.Infrastructure/Logging/EnabledLogger.cs @@ -0,0 +1,77 @@ +namespace SharpArch.Infrastructure.Logging +{ + using System; + using JetBrains.Annotations; + using Microsoft.Extensions.Logging; + + + /// + /// Skips call to to prevent unnecessary memory allocations. + /// + public readonly struct LogWrapper + { + [NotNull] readonly ILogger _logger; + + /// + /// Constructor. + /// + /// Logger. + public LogWrapper([NotNull] ILogger logger) + { + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + } + + /// + /// Logs that contain the most detailed messages. These messages may contain sensitive application data. + /// These messages are disabled by default and should never be enabled in a production environment. + /// + /// or null if specified log level is not enabled. + public EnabledLogLevel? Trace => _logger.IsEnabled(LogLevel.Trace) + ? new EnabledLogLevel(_logger, LogLevel.Trace) + : null; + + /// + /// Logs that are used for interactive investigation during development. These logs should primarily contain + /// information useful for debugging and have no long-term value. + /// + /// or null if specified log level is not enabled. + public EnabledLogLevel? Debug => _logger.IsEnabled(LogLevel.Trace) + ? new EnabledLogLevel(_logger, LogLevel.Debug) + : null; + + /// + /// Logs that track the general flow of the application. These logs should have long-term value. + /// + /// or null if specified log level is not enabled. + public EnabledLogLevel? Information => _logger.IsEnabled(LogLevel.Trace) + ? new EnabledLogLevel(_logger, LogLevel.Information) + : null; + + /// + /// Logs that highlight an abnormal or unexpected event in the application flow, but do not otherwise cause the + /// application execution to stop. + /// + /// or null if specified log level is not enabled. + public EnabledLogLevel? Warning => _logger.IsEnabled(LogLevel.Trace) + ? new EnabledLogLevel(_logger, LogLevel.Warning) + : null; + + /// + /// Logs that highlight when the current flow of execution is stopped due to a failure. These should indicate a + /// failure in the current activity, not an application-wide failure. + /// + /// or null if specified log level is not enabled. + public EnabledLogLevel? Error => _logger.IsEnabled(LogLevel.Trace) + ? new EnabledLogLevel(_logger, LogLevel.Error) + : null; + + /// + /// Logs that describe an unrecoverable application or system crash, or a catastrophic failure that requires + /// immediate attention. + /// + /// or null if specified log level is not enabled. + public EnabledLogLevel? Critical => _logger.IsEnabled(LogLevel.Trace) + ? new EnabledLogLevel(_logger, LogLevel.Critical) + : null; + } +} diff --git a/Src/SharpArch.Infrastructure/SharpArch.Infrastructure.csproj b/Src/SharpArch.Infrastructure/SharpArch.Infrastructure.csproj index d83e240c2..90eabbfe9 100644 --- a/Src/SharpArch.Infrastructure/SharpArch.Infrastructure.csproj +++ b/Src/SharpArch.Infrastructure/SharpArch.Infrastructure.csproj @@ -1,34 +1,34 @@  - - $(NoWarn);CS1591;CS1572;CS1573 - - - - $(DefineConstants);LIBLOG_EXCLUDE_CODE_COVERAGE - - Provides infrastrucure components for Sharp Architecture application. - $(PackageTags);infrastructure;logging + $(PackageTags);infrastructure icon.png - + + + + + + + + + + + + + - - runtime; build; native; contentfiles; analyzers - all - diff --git a/Src/SharpArch.NHibernate.DependencyInjection/NHibernateRegistrationExtensions.cs b/Src/SharpArch.NHibernate.DependencyInjection/NHibernateRegistrationExtensions.cs index bfe8beaa4..e97a25438 100644 --- a/Src/SharpArch.NHibernate.DependencyInjection/NHibernateRegistrationExtensions.cs +++ b/Src/SharpArch.NHibernate.DependencyInjection/NHibernateRegistrationExtensions.cs @@ -15,11 +15,9 @@ [PublicAPI] public static class NHibernateRegistrationExtensions { - static readonly ILog _log = LogProvider.GetLogger("SharpArch.NHibernate.Extensions.DependencyInjection"); - /// /// Adds NHibernate classes required to support , - /// instantiation from container. + /// instantiation from container. /// /// and are registered as Singleton. /// @@ -57,12 +55,14 @@ public static IServiceCollection AddNHibernateWithSingleDatabase( services.AddSingleton(sp => { - _log.Debug("Building session factory..."); + var logger = GetLogger(sp); + + logger.Debug?.Log("Building session factory..."); var sfBuilder = configureSessionFactory(sp); var sessionFactory = sfBuilder.BuildSessionFactory(); - _log.Info("Build session factory {SessionFactoryId}", sessionFactory.GetHashCode()); + logger.Information?.Log("Build session factory {SessionFactoryId}", sessionFactory.GetHashCode()); return sessionFactory; }); @@ -73,7 +73,7 @@ public static IServiceCollection AddNHibernateWithSingleDatabase( ? sessionFactory.OpenSession() : sessionConfigurator(sessionFactory.WithOptions(), sp); - if (_log.IsDebugEnabled()) _log.Debug("Created Session {SessionId}", session.GetSessionImplementation().SessionId); + GetLogger(sp).Debug?.Log("Created Session {SessionId}", session.GetSessionImplementation().SessionId); return session; }); @@ -85,7 +85,7 @@ public static IServiceCollection AddNHibernateWithSingleDatabase( ? sessionFactory.OpenStatelessSession() : statelessSessionConfigurator(sessionFactory.WithStatelessOptions(), sp); - if (_log.IsDebugEnabled()) _log.Debug("Created stateless Session {SessionId}", session.GetSessionImplementation().SessionId); + GetLogger(sp).Debug?.Log("Created stateless Session {SessionId}", session.GetSessionImplementation().SessionId); return session; }); @@ -96,5 +96,12 @@ public static IServiceCollection AddNHibernateWithSingleDatabase( return services; } + + static LogWrapper GetLogger([NotNull] IServiceProvider sp) + { + var logger = new LogWrapper(sp.GetRequiredService() + .CreateLogger("SharpArch.NHibernate.Extensions.DependencyInjection")); + return logger; + } } } diff --git a/Src/SharpArch.Web.AspNetCore/Transaction/AutoTransactionHandler.cs b/Src/SharpArch.Web.AspNetCore/Transaction/AutoTransactionHandler.cs index 131fc6729..7dd1d0c5e 100644 --- a/Src/SharpArch.Web.AspNetCore/Transaction/AutoTransactionHandler.cs +++ b/Src/SharpArch.Web.AspNetCore/Transaction/AutoTransactionHandler.cs @@ -2,10 +2,10 @@ { using System.Threading.Tasks; using Domain.PersistenceSupport; - using Infrastructure.Logging; using JetBrains.Annotations; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Logging; /// @@ -17,8 +17,6 @@ [PublicAPI] public class AutoTransactionHandler : ApplyTransactionFilterBase, IAsyncActionFilter { - static readonly ILog _log = LogProvider.For(); - /// /// is not registered in container. public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) @@ -33,26 +31,24 @@ public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionE var executedContext = await next().ConfigureAwait(false); - if (transactionManager != null) + if (transactionManager is ISupportsTransactionStatus tranStatus) { - if (transactionManager is ISupportsTransactionStatus tranStatus) + if (!tranStatus.IsActive) { - if (!tranStatus.IsActive) - { - _log.Debug("Transaction is already closed"); - return; - } + var logger = context.HttpContext.RequestServices.GetService>(); + logger?.LogDebug("Transaction is already closed"); + return; + } - if (executedContext.Exception != null || - transactionAttribute.RollbackOnModelValidationError && context.ModelState.IsValid == false) - { - // don't use cancellation token to ensure transaction is rolled back on error - await transactionManager.RollbackTransactionAsync().ConfigureAwait(false); - } - else - { - await transactionManager.CommitTransactionAsync(context.HttpContext.RequestAborted).ConfigureAwait(false); - } + if (executedContext.Exception != null || + transactionAttribute.RollbackOnModelValidationError && context.ModelState.IsValid == false) + { + // don't use cancellation token to ensure transaction is rolled back on error + await transactionManager.RollbackTransactionAsync().ConfigureAwait(false); + } + else + { + await transactionManager.CommitTransactionAsync(context.HttpContext.RequestAborted).ConfigureAwait(false); } } } From f835eb06873f6da5c8ae8cdfd5360e486eb0e905 Mon Sep 17 00:00:00 2001 From: vk Date: Thu, 28 Jan 2021 23:11:45 -0500 Subject: [PATCH 08/13] Upgrade build dependencies, closes #240 --- dotnet-install.ps1 | 699 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 594 insertions(+), 105 deletions(-) diff --git a/dotnet-install.ps1 b/dotnet-install.ps1 index 14ebe11af..a502c8513 100644 --- a/dotnet-install.ps1 +++ b/dotnet-install.ps1 @@ -15,36 +15,33 @@ - Current - most current release - LTS - most current supported release - 2-part version in a format A.B - represents a specific release - examples: 2.0; 1.0 + examples: 2.0, 1.0 - Branch name - examples: release/2.0.0; Master + examples: release/2.0.0, Master + Note: The version parameter overrides the channel parameter. .PARAMETER Version Default: latest Represents a build version on specific channel. Possible values: - latest - most latest build on specific channel - - coherent - most latest coherent build on specific channel - coherent applies only to SDK downloads - 3-part version in a format A.B.C - represents specific version of build - examples: 2.0.0-preview2-006120; 1.1.0 + examples: 2.0.0-preview2-006120, 1.1.0 .PARAMETER InstallDir Default: %LocalAppData%\Microsoft\dotnet Path to where to install dotnet. Note that binaries will be placed directly in a given directory. .PARAMETER Architecture Default: - this value represents currently running OS architecture Architecture of dotnet binaries to be installed. - Possible values are: , x64 and x86 + Possible values are: , amd64, x64, x86, arm64, arm .PARAMETER SharedRuntime This parameter is obsolete and may be removed in a future version of this script. The recommended alternative is '-Runtime dotnet'. - - Default: false Installs just the shared runtime bits, not the entire SDK. - This is equivalent to specifying `-Runtime dotnet`. .PARAMETER Runtime Installs just a shared runtime, not the entire SDK. Possible values: - dotnet - the Microsoft.NETCore.App shared runtime - aspnetcore - the Microsoft.AspNetCore.App shared runtime + - windowsdesktop - the Microsoft.WindowsDesktop.App shared runtime .PARAMETER DryRun If set it will not perform installation but instead display what command line to use to consistently install currently requested version of dotnet cli. In example if you specify version 'latest' it will display a link @@ -70,19 +67,25 @@ .PARAMETER ProxyUseDefaultCredentials Default: false Use default credentials, when using proxy address. +.PARAMETER ProxyBypassList + If set with ProxyAddress, will provide the list of comma separated urls that will bypass the proxy .PARAMETER SkipNonVersionedFiles Default: false Skips installing non-versioned files if they already exist, such as dotnet.exe. .PARAMETER NoCdn Disable downloading from the Azure CDN, and use the uncached feed directly. +.PARAMETER JSonFile + Determines the SDK version from a user specified global.json file + Note: global.json must have a value for 'SDK:Version' #> [cmdletbinding()] param( [string]$Channel="LTS", [string]$Version="Latest", + [string]$JSonFile, [string]$InstallDir="", [string]$Architecture="", - [ValidateSet("dotnet", "aspnetcore", IgnoreCase = $false)] + [ValidateSet("dotnet", "aspnetcore", "windowsdesktop", IgnoreCase = $false)] [string]$Runtime, [Obsolete("This parameter may be removed in a future version of this script. The recommended alternative is '-Runtime dotnet'.")] [switch]$SharedRuntime, @@ -93,6 +96,7 @@ param( [string]$FeedCredential, [string]$ProxyAddress, [switch]$ProxyUseDefaultCredentials, + [string[]]$ProxyBypassList=@(), [switch]$SkipNonVersionedFiles, [switch]$NoCdn ) @@ -116,11 +120,45 @@ $VersionRegEx="/\d+\.\d+[^/]+/" $OverrideNonVersionedFiles = !$SkipNonVersionedFiles function Say($str) { - Write-Host "dotnet-install: $str" + try { + Write-Host "dotnet-install: $str" + } + catch { + # Some platforms cannot utilize Write-Host (Azure Functions, for instance). Fall back to Write-Output + Write-Output "dotnet-install: $str" + } +} + +function Say-Warning($str) { + try { + Write-Warning "dotnet-install: $str" + } + catch { + # Some platforms cannot utilize Write-Warning (Azure Functions, for instance). Fall back to Write-Output + Write-Output "dotnet-install: Warning: $str" + } +} + +# Writes a line with error style settings. +# Use this function to show a human-readable comment along with an exception. +function Say-Error($str) { + try { + # Write-Error is quite oververbose for the purpose of the function, let's write one line with error style settings. + $Host.UI.WriteErrorLine("dotnet-install: $str") + } + catch { + Write-Output "dotnet-install: Error: $str" + } } function Say-Verbose($str) { - Write-Verbose "dotnet-install: $str" + try { + Write-Verbose "dotnet-install: $str" + } + catch { + # Some platforms cannot utilize Write-Verbose (Azure Functions, for instance). Fall back to Write-Output + Write-Output "dotnet-install: $str" + } } function Say-Invocation($Invocation) { @@ -134,7 +172,7 @@ function Invoke-With-Retry([ScriptBlock]$ScriptBlock, [int]$MaxAttempts = 3, [in while ($true) { try { - return $ScriptBlock.Invoke() + return & $ScriptBlock } catch { $Attempts++ @@ -151,11 +189,19 @@ function Invoke-With-Retry([ScriptBlock]$ScriptBlock, [int]$MaxAttempts = 3, [in function Get-Machine-Architecture() { Say-Invocation $MyInvocation - # possible values: AMD64, IA64, x86 + # On PS x86, PROCESSOR_ARCHITECTURE reports x86 even on x64 systems. + # To get the correct architecture, we need to use PROCESSOR_ARCHITEW6432. + # PS x64 doesn't define this, so we fall back to PROCESSOR_ARCHITECTURE. + # Possible values: amd64, x64, x86, arm64, arm + + if( $ENV:PROCESSOR_ARCHITEW6432 -ne $null ) + { + return $ENV:PROCESSOR_ARCHITEW6432 + } + return $ENV:PROCESSOR_ARCHITECTURE } -# TODO: Architecture and CLIArchitecture should be unified function Get-CLIArchitecture-From-Architecture([string]$Architecture) { Say-Invocation $MyInvocation @@ -163,18 +209,27 @@ function Get-CLIArchitecture-From-Architecture([string]$Architecture) { { $_ -eq "" } { return Get-CLIArchitecture-From-Architecture $(Get-Machine-Architecture) } { ($_ -eq "amd64") -or ($_ -eq "x64") } { return "x64" } { $_ -eq "x86" } { return "x86" } - default { throw "Architecture not supported. If you think this is a bug, please report it at https://github.com/dotnet/cli/issues" } + { $_ -eq "arm" } { return "arm" } + { $_ -eq "arm64" } { return "arm64" } + default { throw "Architecture '$Architecture' not supported. If you think this is a bug, report it at https://github.com/dotnet/install-scripts/issues" } } } +# The version text returned from the feeds is a 1-line or 2-line string: +# For the SDK and the dotnet runtime (2 lines): +# Line 1: # commit_hash +# Line 2: # 4-part version +# For the aspnetcore runtime (1 line): +# Line 1: # 4-part version function Get-Version-Info-From-Version-Text([string]$VersionText) { Say-Invocation $MyInvocation - $Data = @($VersionText.Split([char[]]@(), [StringSplitOptions]::RemoveEmptyEntries)); + $Data = -split $VersionText - $VersionInfo = @{} - $VersionInfo.CommitHash = $Data[0].Trim() - $VersionInfo.Version = $Data[1].Trim() + $VersionInfo = @{ + CommitHash = $(if ($Data.Count -gt 1) { $Data[0] }) + Version = $Data[-1] # last line is always the version number. + } return $VersionInfo } @@ -217,7 +272,11 @@ function GetHTTPResponse([Uri] $Uri) if($ProxyAddress) { $HttpClientHandler = New-Object System.Net.Http.HttpClientHandler - $HttpClientHandler.Proxy = New-Object System.Net.WebProxy -Property @{Address=$ProxyAddress;UseDefaultCredentials=$ProxyUseDefaultCredentials} + $HttpClientHandler.Proxy = New-Object System.Net.WebProxy -Property @{ + Address=$ProxyAddress; + UseDefaultCredentials=$ProxyUseDefaultCredentials; + BypassList = $ProxyBypassList; + } $HttpClient = New-Object System.Net.Http.HttpClient -ArgumentList $HttpClientHandler } else { @@ -225,20 +284,43 @@ function GetHTTPResponse([Uri] $Uri) $HttpClient = New-Object System.Net.Http.HttpClient } # Default timeout for HttpClient is 100s. For a 50 MB download this assumes 500 KB/s average, any less will time out - # 10 minutes allows it to work over much slower connections. - $HttpClient.Timeout = New-TimeSpan -Minutes 10 - $Response = $HttpClient.GetAsync("${Uri}${FeedCredential}").Result - if (($Response -eq $null) -or (-not ($Response.IsSuccessStatusCode))) { - # The feed credential is potentially sensitive info. Do not log FeedCredential to console output. - $ErrorMsg = "Failed to download $Uri." - if ($Response -ne $null) { - $ErrorMsg += " $Response" + # 20 minutes allows it to work over much slower connections. + $HttpClient.Timeout = New-TimeSpan -Minutes 20 + $Task = $HttpClient.GetAsync("${Uri}${FeedCredential}").ConfigureAwait("false"); + $Response = $Task.GetAwaiter().GetResult(); + + if (($null -eq $Response) -or (-not ($Response.IsSuccessStatusCode))) { + # The feed credential is potentially sensitive info. Do not log FeedCredential to console output. + $DownloadException = [System.Exception] "Unable to download $Uri." + + if ($null -ne $Response) { + $DownloadException.Data["StatusCode"] = [int] $Response.StatusCode + $DownloadException.Data["ErrorMessage"] = "Unable to download $Uri. Returned HTTP status code: " + $DownloadException.Data["StatusCode"] } - throw $ErrorMsg + throw $DownloadException + } + + return $Response + } + catch [System.Net.Http.HttpRequestException] { + $DownloadException = [System.Exception] "Unable to download $Uri." + + # Pick up the exception message and inner exceptions' messages if they exist + $CurrentException = $PSItem.Exception + $ErrorMsg = $CurrentException.Message + "`r`n" + while ($CurrentException.InnerException) { + $CurrentException = $CurrentException.InnerException + $ErrorMsg += $CurrentException.Message + "`r`n" + } + + # Check if there is an issue concerning TLS. + if ($ErrorMsg -like "*SSL/TLS*") { + $ErrorMsg += "Ensure that TLS 1.2 or higher is enabled to use this script.`r`n" } - return $Response + $DownloadException.Data["ErrorMessage"] = $ErrorMsg + throw $DownloadException } finally { if ($HttpClient -ne $null) { @@ -248,8 +330,7 @@ function GetHTTPResponse([Uri] $Uri) }) } - -function Get-Latest-Version-Info([string]$AzureFeed, [string]$Channel, [bool]$Coherent) { +function Get-Latest-Version-Info([string]$AzureFeed, [string]$Channel) { Say-Invocation $MyInvocation $VersionFileUrl = $null @@ -259,19 +340,23 @@ function Get-Latest-Version-Info([string]$AzureFeed, [string]$Channel, [bool]$Co elseif ($Runtime -eq "aspnetcore") { $VersionFileUrl = "$UncachedFeed/aspnetcore/Runtime/$Channel/latest.version" } + # Currently, the WindowsDesktop runtime is manufactured with the .Net core runtime + elseif ($Runtime -eq "windowsdesktop") { + $VersionFileUrl = "$UncachedFeed/Runtime/$Channel/latest.version" + } elseif (-not $Runtime) { - if ($Coherent) { - $VersionFileUrl = "$UncachedFeed/Sdk/$Channel/latest.coherent.version" - } - else { - $VersionFileUrl = "$UncachedFeed/Sdk/$Channel/latest.version" - } + $VersionFileUrl = "$UncachedFeed/Sdk/$Channel/latest.version" } else { throw "Invalid value for `$Runtime" } - - $Response = GetHTTPResponse -Uri $VersionFileUrl + try { + $Response = GetHTTPResponse -Uri $VersionFileUrl + } + catch { + Say-Error "Could not resolve version information." + throw + } $StringContent = $Response.Content.ReadAsStringAsync().Result switch ($Response.Content.Headers.ContentType) { @@ -286,42 +371,85 @@ function Get-Latest-Version-Info([string]$AzureFeed, [string]$Channel, [bool]$Co return $VersionInfo } +function Parse-Jsonfile-For-Version([string]$JSonFile) { + Say-Invocation $MyInvocation -function Get-Specific-Version-From-Version([string]$AzureFeed, [string]$Channel, [string]$Version) { + If (-Not (Test-Path $JSonFile)) { + throw "Unable to find '$JSonFile'" + } + try { + $JSonContent = Get-Content($JSonFile) -Raw | ConvertFrom-Json | Select-Object -expand "sdk" -ErrorAction SilentlyContinue + } + catch { + Say-Error "Json file unreadable: '$JSonFile'" + throw + } + if ($JSonContent) { + try { + $JSonContent.PSObject.Properties | ForEach-Object { + $PropertyName = $_.Name + if ($PropertyName -eq "version") { + $Version = $_.Value + Say-Verbose "Version = $Version" + } + } + } + catch { + Say-Error "Unable to parse the SDK node in '$JSonFile'" + throw + } + } + else { + throw "Unable to find the SDK node in '$JSonFile'" + } + If ($Version -eq $null) { + throw "Unable to find the SDK:version node in '$JSonFile'" + } + return $Version +} + +function Get-Specific-Version-From-Version([string]$AzureFeed, [string]$Channel, [string]$Version, [string]$JSonFile) { Say-Invocation $MyInvocation - switch ($Version.ToLower()) { - { $_ -eq "latest" } { - $LatestVersionInfo = Get-Latest-Version-Info -AzureFeed $AzureFeed -Channel $Channel -Coherent $False + if (-not $JSonFile) { + if ($Version.ToLower() -eq "latest") { + $LatestVersionInfo = Get-Latest-Version-Info -AzureFeed $AzureFeed -Channel $Channel return $LatestVersionInfo.Version } - { $_ -eq "coherent" } { - $LatestVersionInfo = Get-Latest-Version-Info -AzureFeed $AzureFeed -Channel $Channel -Coherent $True - return $LatestVersionInfo.Version + else { + return $Version } - default { return $Version } + } + else { + return Parse-Jsonfile-For-Version $JSonFile } } function Get-Download-Link([string]$AzureFeed, [string]$SpecificVersion, [string]$CLIArchitecture) { Say-Invocation $MyInvocation + # If anything fails in this lookup it will default to $SpecificVersion + $SpecificProductVersion = Get-Product-Version -AzureFeed $AzureFeed -SpecificVersion $SpecificVersion + if ($Runtime -eq "dotnet") { - $PayloadURL = "$AzureFeed/Runtime/$SpecificVersion/dotnet-runtime-$SpecificVersion-win-$CLIArchitecture.zip" + $PayloadURL = "$AzureFeed/Runtime/$SpecificVersion/dotnet-runtime-$SpecificProductVersion-win-$CLIArchitecture.zip" } elseif ($Runtime -eq "aspnetcore") { - $PayloadURL = "$AzureFeed/aspnetcore/Runtime/$SpecificVersion/aspnetcore-runtime-$SpecificVersion-win-$CLIArchitecture.zip" + $PayloadURL = "$AzureFeed/aspnetcore/Runtime/$SpecificVersion/aspnetcore-runtime-$SpecificProductVersion-win-$CLIArchitecture.zip" + } + elseif ($Runtime -eq "windowsdesktop") { + $PayloadURL = "$AzureFeed/Runtime/$SpecificVersion/windowsdesktop-runtime-$SpecificProductVersion-win-$CLIArchitecture.zip" } elseif (-not $Runtime) { - $PayloadURL = "$AzureFeed/Sdk/$SpecificVersion/dotnet-sdk-$SpecificVersion-win-$CLIArchitecture.zip" + $PayloadURL = "$AzureFeed/Sdk/$SpecificVersion/dotnet-sdk-$SpecificProductVersion-win-$CLIArchitecture.zip" } else { throw "Invalid value for `$Runtime" } - Say-Verbose "Constructed primary payload URL: $PayloadURL" + Say-Verbose "Constructed primary named payload URL: $PayloadURL" - return $PayloadURL + return $PayloadURL, $SpecificProductVersion } function Get-LegacyDownload-Link([string]$AzureFeed, [string]$SpecificVersion, [string]$CLIArchitecture) { @@ -337,11 +465,56 @@ function Get-LegacyDownload-Link([string]$AzureFeed, [string]$SpecificVersion, [ return $null } - Say-Verbose "Constructed legacy payload URL: $PayloadURL" + Say-Verbose "Constructed legacy named payload URL: $PayloadURL" return $PayloadURL } +function Get-Product-Version([string]$AzureFeed, [string]$SpecificVersion) { + Say-Invocation $MyInvocation + + if ($Runtime -eq "dotnet") { + $ProductVersionTxtURL = "$AzureFeed/Runtime/$SpecificVersion/productVersion.txt" + } + elseif ($Runtime -eq "aspnetcore") { + $ProductVersionTxtURL = "$AzureFeed/aspnetcore/Runtime/$SpecificVersion/productVersion.txt" + } + elseif ($Runtime -eq "windowsdesktop") { + $ProductVersionTxtURL = "$AzureFeed/Runtime/$SpecificVersion/productVersion.txt" + } + elseif (-not $Runtime) { + $ProductVersionTxtURL = "$AzureFeed/Sdk/$SpecificVersion/productVersion.txt" + } + else { + throw "Invalid value '$Runtime' specified for `$Runtime" + } + + Say-Verbose "Checking for existence of $ProductVersionTxtURL" + + try { + $productVersionResponse = GetHTTPResponse($productVersionTxtUrl) + + if ($productVersionResponse.StatusCode -eq 200) { + $productVersion = $productVersionResponse.Content.ReadAsStringAsync().Result.Trim() + if ($productVersion -ne $SpecificVersion) + { + Say "Using alternate version $productVersion found in $ProductVersionTxtURL" + } + + return $productVersion + } + else { + Say-Verbose "Got StatusCode $($productVersionResponse.StatusCode) trying to get productVersion.txt at $productVersionTxtUrl, so using default value of $SpecificVersion" + $productVersion = $SpecificVersion + } + } catch { + Say-Verbose "Could not read productVersion.txt at $productVersionTxtUrl, so using default value of $SpecificVersion (Exception: '$($_.Exception.Message)' )" + $productVersion = $SpecificVersion + } + + return $productVersion +} + function Get-User-Share-Path() { Say-Invocation $MyInvocation @@ -361,28 +534,11 @@ function Resolve-Installation-Path([string]$InstallDir) { return $InstallDir } -function Get-Version-Info-From-Version-File([string]$InstallRoot, [string]$RelativePathToVersionFile) { - Say-Invocation $MyInvocation - - $VersionFile = Join-Path -Path $InstallRoot -ChildPath $RelativePathToVersionFile - Say-Verbose "Local version file: $VersionFile" - - if (Test-Path $VersionFile) { - $VersionText = cat $VersionFile - Say-Verbose "Local version file text: $VersionText" - return Get-Version-Info-From-Version-Text $VersionText - } - - Say-Verbose "Local version file not found." - - return $null -} - function Is-Dotnet-Package-Installed([string]$InstallRoot, [string]$RelativePathToPackage, [string]$SpecificVersion) { Say-Invocation $MyInvocation $DotnetPackagePath = Join-Path -Path $InstallRoot -ChildPath $RelativePathToPackage | Join-Path -ChildPath $SpecificVersion - Say-Verbose "Is-Dotnet-Package-Installed: Path to a package: $DotnetPackagePath" + Say-Verbose "Is-Dotnet-Package-Installed: DotnetPackagePath=$DotnetPackagePath" return Test-Path $DotnetPackagePath -PathType Container } @@ -467,17 +623,23 @@ function Extract-Dotnet-Package([string]$ZipPath, [string]$OutPath) { } } -function DownloadFile([Uri]$Uri, [string]$OutPath) { - if ($Uri -notlike "http*") { - Say-Verbose "Copying file from $Uri to $OutPath" - Copy-Item $Uri.AbsolutePath $OutPath +function DownloadFile($Source, [string]$OutPath) { + if ($Source -notlike "http*") { + # Using System.IO.Path.GetFullPath to get the current directory + # does not work in this context - $pwd gives the current directory + if (![System.IO.Path]::IsPathRooted($Source)) { + $Source = $(Join-Path -Path $pwd -ChildPath $Source) + } + $Source = Get-Absolute-Path $Source + Say "Copying file from $Source to $OutPath" + Copy-Item $Source $OutPath return } $Stream = $null try { - $Response = GetHTTPResponse -Uri $Uri + $Response = GetHTTPResponse -Uri $Source $Stream = $Response.Content.ReadAsStreamAsync().Result $File = [System.IO.File]::Create($OutPath) $Stream.CopyTo($File) @@ -490,34 +652,79 @@ function DownloadFile([Uri]$Uri, [string]$OutPath) { } } +function SafeRemoveFile($Path) { + try { + if (Test-Path $Path) { + Remove-Item $Path + Say-Verbose "The temporary file `"$Path`" was removed." + } + else + { + Say-Verbose "The temporary file `"$Path`" does not exist, therefore is not removed." + } + } + catch + { + Say-Warning "Failed to remove the temporary file: `"$Path`", remove it manually." + } +} + function Prepend-Sdk-InstallRoot-To-Path([string]$InstallRoot, [string]$BinFolderRelativePath) { $BinPath = Get-Absolute-Path $(Join-Path -Path $InstallRoot -ChildPath $BinFolderRelativePath) if (-Not $NoPath) { - Say "Adding to current process PATH: `"$BinPath`". Note: This change will not be visible if PowerShell was run as a child process." - $env:path = "$BinPath;" + $env:path + $SuffixedBinPath = "$BinPath;" + if (-Not $env:path.Contains($SuffixedBinPath)) { + Say "Adding to current process PATH: `"$BinPath`". Note: This change will not be visible if PowerShell was run as a child process." + $env:path = $SuffixedBinPath + $env:path + } else { + Say-Verbose "Current process PATH already contains `"$BinPath`"" + } } else { Say "Binaries of dotnet can be found in $BinPath" } } +Say "Note that the intended use of this script is for Continuous Integration (CI) scenarios, where:" +Say "- The SDK needs to be installed without user interaction and without admin rights." +Say "- The SDK installation doesn't need to persist across multiple CI runs." +Say "To set up a development environment or to run apps, use installers rather than this script. Visit https://dotnet.microsoft.com/download to get the installer.`r`n" + $CLIArchitecture = Get-CLIArchitecture-From-Architecture $Architecture -$SpecificVersion = Get-Specific-Version-From-Version -AzureFeed $AzureFeed -Channel $Channel -Version $Version -$DownloadLink = Get-Download-Link -AzureFeed $AzureFeed -SpecificVersion $SpecificVersion -CLIArchitecture $CLIArchitecture +$SpecificVersion = Get-Specific-Version-From-Version -AzureFeed $AzureFeed -Channel $Channel -Version $Version -JSonFile $JSonFile +$DownloadLink, $EffectiveVersion = Get-Download-Link -AzureFeed $AzureFeed -SpecificVersion $SpecificVersion -CLIArchitecture $CLIArchitecture $LegacyDownloadLink = Get-LegacyDownload-Link -AzureFeed $AzureFeed -SpecificVersion $SpecificVersion -CLIArchitecture $CLIArchitecture +$InstallRoot = Resolve-Installation-Path $InstallDir +Say-Verbose "InstallRoot: $InstallRoot" +$ScriptName = $MyInvocation.MyCommand.Name + if ($DryRun) { Say "Payload URLs:" - Say "Primary - $DownloadLink" + Say "Primary named payload URL: $DownloadLink" if ($LegacyDownloadLink) { - Say "Legacy - $LegacyDownloadLink" + Say "Legacy named payload URL: $LegacyDownloadLink" + } + $RepeatableCommand = ".\$ScriptName -Version `"$SpecificVersion`" -InstallDir `"$InstallRoot`" -Architecture `"$CLIArchitecture`"" + if ($Runtime -eq "dotnet") { + $RepeatableCommand+=" -Runtime `"dotnet`"" + } + elseif ($Runtime -eq "aspnetcore") { + $RepeatableCommand+=" -Runtime `"aspnetcore`"" + } + foreach ($key in $MyInvocation.BoundParameters.Keys) { + if (-not (@("Architecture","Channel","DryRun","InstallDir","Runtime","SharedRuntime","Version") -contains $key)) { + $RepeatableCommand+=" -$key `"$($MyInvocation.BoundParameters[$key])`"" + } + } + Say "Repeatable invocation: $RepeatableCommand" + if ($SpecificVersion -ne $EffectiveVersion) + { + Say "NOTE: Due to finding a version manifest with this runtime, it would actually install with version '$EffectiveVersion'" } - Say "Repeatable invocation: .\$($MyInvocation.Line)" - exit 0 -} -$InstallRoot = Resolve-Installation-Path $InstallDir -Say-Verbose "InstallRoot: $InstallRoot" + return +} if ($Runtime -eq "dotnet") { $assetName = ".NET Core Runtime" @@ -527,6 +734,10 @@ elseif ($Runtime -eq "aspnetcore") { $assetName = "ASP.NET Core Runtime" $dotnetPackageRelativePath = "shared\Microsoft.AspNetCore.App" } +elseif ($Runtime -eq "windowsdesktop") { + $assetName = ".NET Core Windows Desktop Runtime" + $dotnetPackageRelativePath = "shared\Microsoft.WindowsDesktop.App" +} elseif (-not $Runtime) { $assetName = ".NET Core SDK" $dotnetPackageRelativePath = "sdk" @@ -535,55 +746,333 @@ else { throw "Invalid value for `$Runtime" } +if ($SpecificVersion -ne $EffectiveVersion) +{ + Say "Performing installation checks for effective version: $EffectiveVersion" + $SpecificVersion = $EffectiveVersion +} + # Check if the SDK version is already installed. $isAssetInstalled = Is-Dotnet-Package-Installed -InstallRoot $InstallRoot -RelativePathToPackage $dotnetPackageRelativePath -SpecificVersion $SpecificVersion if ($isAssetInstalled) { Say "$assetName version $SpecificVersion is already installed." Prepend-Sdk-InstallRoot-To-Path -InstallRoot $InstallRoot -BinFolderRelativePath $BinFolderRelativePath - exit 0 + return } New-Item -ItemType Directory -Force -Path $InstallRoot | Out-Null $installDrive = $((Get-Item $InstallRoot).PSDrive.Name); -$free = Get-CimInstance -Class win32_logicaldisk | where Deviceid -eq "${installDrive}:" -if ($free.Freespace / 1MB -le 100 ) { - Say "There is not enough disk space on drive ${installDrive}:" - exit 0 +$diskInfo = Get-PSDrive -Name $installDrive +if ($diskInfo.Free / 1MB -le 100) { + throw "There is not enough disk space on drive ${installDrive}:" } $ZipPath = [System.IO.Path]::combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName()) Say-Verbose "Zip path: $ZipPath" -Say "Downloading link: $DownloadLink" + +$DownloadFailed = $false + +$PrimaryDownloadStatusCode = 0 +$LegacyDownloadStatusCode = 0 + +$PrimaryDownloadFailedMsg = "" +$LegacyDownloadFailedMsg = "" + +Say "Downloading primary link $DownloadLink" try { - DownloadFile -Uri $DownloadLink -OutPath $ZipPath + DownloadFile -Source $DownloadLink -OutPath $ZipPath } catch { - Say "Cannot download: $DownloadLink" + if ($PSItem.Exception.Data.Contains("StatusCode")) { + $PrimaryDownloadStatusCode = $PSItem.Exception.Data["StatusCode"] + } + + if ($PSItem.Exception.Data.Contains("ErrorMessage")) { + $PrimaryDownloadFailedMsg = $PSItem.Exception.Data["ErrorMessage"] + } else { + $PrimaryDownloadFailedMsg = $PSItem.Exception.Message + } + + if ($PrimaryDownloadStatusCode -eq 404) { + Say "The resource at $DownloadLink is not available." + } else { + Say $PSItem.Exception.Message + } + + SafeRemoveFile -Path $ZipPath + if ($LegacyDownloadLink) { $DownloadLink = $LegacyDownloadLink $ZipPath = [System.IO.Path]::combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName()) Say-Verbose "Legacy zip path: $ZipPath" - Say "Downloading legacy link: $DownloadLink" - DownloadFile -Uri $DownloadLink -OutPath $ZipPath + Say "Downloading legacy link $DownloadLink" + try { + DownloadFile -Source $DownloadLink -OutPath $ZipPath + } + catch { + if ($PSItem.Exception.Data.Contains("StatusCode")) { + $LegacyDownloadStatusCode = $PSItem.Exception.Data["StatusCode"] + } + + if ($PSItem.Exception.Data.Contains("ErrorMessage")) { + $LegacyDownloadFailedMsg = $PSItem.Exception.Data["ErrorMessage"] + } else { + $LegacyDownloadFailedMsg = $PSItem.Exception.Message + } + + if ($LegacyDownloadStatusCode -eq 404) { + Say "The resource at $DownloadLink is not available." + } else { + Say $PSItem.Exception.Message + } + + SafeRemoveFile -Path $ZipPath + $DownloadFailed = $true + } } else { - throw "Could not download $assetName version $SpecificVersion" + $DownloadFailed = $true + } +} + +if ($DownloadFailed) { + if (($PrimaryDownloadStatusCode -eq 404) -and ((-not $LegacyDownloadLink) -or ($LegacyDownloadStatusCode -eq 404))) { + throw "Could not find `"$assetName`" with version = $SpecificVersion`nRefer to: https://aka.ms/dotnet-os-lifecycle for information on .NET Core support" + } else { + # 404-NotFound is an expected response if it goes from only one of the links, do not show that error. + # If primary path is available (not 404-NotFound) then show the primary error else show the legacy error. + if ($PrimaryDownloadStatusCode -ne 404) { + throw "Could not download `"$assetName`" with version = $SpecificVersion`r`n$PrimaryDownloadFailedMsg" + } + if (($LegacyDownloadLink) -and ($LegacyDownloadStatusCode -ne 404)) { + throw "Could not download `"$assetName`" with version = $SpecificVersion`r`n$LegacyDownloadFailedMsg" + } + throw "Could not download `"$assetName`" with version = $SpecificVersion" } } Say "Extracting zip from $DownloadLink" Extract-Dotnet-Package -ZipPath $ZipPath -OutPath $InstallRoot -# Check if the SDK version is now installed; if not, fail the installation. -$isAssetInstalled = Is-Dotnet-Package-Installed -InstallRoot $InstallRoot -RelativePathToPackage $dotnetPackageRelativePath -SpecificVersion $SpecificVersion +# Check if the SDK version is installed; if not, fail the installation. +$isAssetInstalled = $false + +# if the version contains "RTM" or "servicing"; check if a 'release-type' SDK version is installed. +if ($SpecificVersion -Match "rtm" -or $SpecificVersion -Match "servicing") { + $ReleaseVersion = $SpecificVersion.Split("-")[0] + Say-Verbose "Checking installation: version = $ReleaseVersion" + $isAssetInstalled = Is-Dotnet-Package-Installed -InstallRoot $InstallRoot -RelativePathToPackage $dotnetPackageRelativePath -SpecificVersion $ReleaseVersion +} + +# Check if the SDK version is installed. +if (!$isAssetInstalled) { + Say-Verbose "Checking installation: version = $SpecificVersion" + $isAssetInstalled = Is-Dotnet-Package-Installed -InstallRoot $InstallRoot -RelativePathToPackage $dotnetPackageRelativePath -SpecificVersion $SpecificVersion +} + +# Version verification failed. More likely something is wrong either with the downloaded content or with the verification algorithm. if (!$isAssetInstalled) { - throw "$assetName version $SpecificVersion failed to install with an unknown error." + Say-Error "Failed to verify the version of installed `"$assetName`".`nInstallation source: $DownloadLink.`nInstallation location: $InstallRoot.`nReport the bug at https://github.com/dotnet/install-scripts/issues." + throw "`"$assetName`" with version = $SpecificVersion failed to install with an unknown error." } -Remove-Item $ZipPath +SafeRemoveFile -Path $ZipPath Prepend-Sdk-InstallRoot-To-Path -InstallRoot $InstallRoot -BinFolderRelativePath $BinFolderRelativePath +Say "Note that the script does not resolve dependencies during installation." +Say "To check the list of dependencies, go to https://docs.microsoft.com/dotnet/core/install/windows#dependencies" Say "Installation finished" -exit 0 +# SIG # Begin signature block +# MIIjkgYJKoZIhvcNAQcCoIIjgzCCI38CAQExDzANBglghkgBZQMEAgEFADB5Bgor +# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG +# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCD2c707qnCLOLIC +# n6Mu5Gr4+Xp68foyZlGlTycnycc5l6CCDYEwggX/MIID56ADAgECAhMzAAABh3IX +# chVZQMcJAAAAAAGHMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD +# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy +# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p +# bmcgUENBIDIwMTEwHhcNMjAwMzA0MTgzOTQ3WhcNMjEwMzAzMTgzOTQ3WjB0MQsw +# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u +# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy +# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +# AQDOt8kLc7P3T7MKIhouYHewMFmnq8Ayu7FOhZCQabVwBp2VS4WyB2Qe4TQBT8aB +# znANDEPjHKNdPT8Xz5cNali6XHefS8i/WXtF0vSsP8NEv6mBHuA2p1fw2wB/F0dH +# sJ3GfZ5c0sPJjklsiYqPw59xJ54kM91IOgiO2OUzjNAljPibjCWfH7UzQ1TPHc4d +# weils8GEIrbBRb7IWwiObL12jWT4Yh71NQgvJ9Fn6+UhD9x2uk3dLj84vwt1NuFQ +# itKJxIV0fVsRNR3abQVOLqpDugbr0SzNL6o8xzOHL5OXiGGwg6ekiXA1/2XXY7yV +# Fc39tledDtZjSjNbex1zzwSXAgMBAAGjggF+MIIBejAfBgNVHSUEGDAWBgorBgEE +# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUhov4ZyO96axkJdMjpzu2zVXOJcsw +# UAYDVR0RBEkwR6RFMEMxKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1 +# ZXJ0byBSaWNvMRYwFAYDVQQFEw0yMzAwMTIrNDU4Mzg1MB8GA1UdIwQYMBaAFEhu +# ZOVQBdOCqhc3NyK1bajKdQKVMFQGA1UdHwRNMEswSaBHoEWGQ2h0dHA6Ly93d3cu +# bWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY0NvZFNpZ1BDQTIwMTFfMjAxMS0w +# Ny0wOC5jcmwwYQYIKwYBBQUHAQEEVTBTMFEGCCsGAQUFBzAChkVodHRwOi8vd3d3 +# Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY0NvZFNpZ1BDQTIwMTFfMjAx +# MS0wNy0wOC5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAgEAixmy +# S6E6vprWD9KFNIB9G5zyMuIjZAOuUJ1EK/Vlg6Fb3ZHXjjUwATKIcXbFuFC6Wr4K +# NrU4DY/sBVqmab5AC/je3bpUpjtxpEyqUqtPc30wEg/rO9vmKmqKoLPT37svc2NV +# BmGNl+85qO4fV/w7Cx7J0Bbqk19KcRNdjt6eKoTnTPHBHlVHQIHZpMxacbFOAkJr +# qAVkYZdz7ikNXTxV+GRb36tC4ByMNxE2DF7vFdvaiZP0CVZ5ByJ2gAhXMdK9+usx +# zVk913qKde1OAuWdv+rndqkAIm8fUlRnr4saSCg7cIbUwCCf116wUJ7EuJDg0vHe +# yhnCeHnBbyH3RZkHEi2ofmfgnFISJZDdMAeVZGVOh20Jp50XBzqokpPzeZ6zc1/g +# yILNyiVgE+RPkjnUQshd1f1PMgn3tns2Cz7bJiVUaqEO3n9qRFgy5JuLae6UweGf +# AeOo3dgLZxikKzYs3hDMaEtJq8IP71cX7QXe6lnMmXU/Hdfz2p897Zd+kU+vZvKI +# 3cwLfuVQgK2RZ2z+Kc3K3dRPz2rXycK5XCuRZmvGab/WbrZiC7wJQapgBodltMI5 +# GMdFrBg9IeF7/rP4EqVQXeKtevTlZXjpuNhhjuR+2DMt/dWufjXpiW91bo3aH6Ea +# jOALXmoxgltCp1K7hrS6gmsvj94cLRf50QQ4U8Qwggd6MIIFYqADAgECAgphDpDS +# AAAAAAADMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMK +# V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0 +# IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0 +# ZSBBdXRob3JpdHkgMjAxMTAeFw0xMTA3MDgyMDU5MDlaFw0yNjA3MDgyMTA5MDla +# MH4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS +# ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMT +# H01pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTEwggIiMA0GCSqGSIb3DQEB +# AQUAA4ICDwAwggIKAoICAQCr8PpyEBwurdhuqoIQTTS68rZYIZ9CGypr6VpQqrgG +# OBoESbp/wwwe3TdrxhLYC/A4wpkGsMg51QEUMULTiQ15ZId+lGAkbK+eSZzpaF7S +# 35tTsgosw6/ZqSuuegmv15ZZymAaBelmdugyUiYSL+erCFDPs0S3XdjELgN1q2jz +# y23zOlyhFvRGuuA4ZKxuZDV4pqBjDy3TQJP4494HDdVceaVJKecNvqATd76UPe/7 +# 4ytaEB9NViiienLgEjq3SV7Y7e1DkYPZe7J7hhvZPrGMXeiJT4Qa8qEvWeSQOy2u +# M1jFtz7+MtOzAz2xsq+SOH7SnYAs9U5WkSE1JcM5bmR/U7qcD60ZI4TL9LoDho33 +# X/DQUr+MlIe8wCF0JV8YKLbMJyg4JZg5SjbPfLGSrhwjp6lm7GEfauEoSZ1fiOIl +# XdMhSz5SxLVXPyQD8NF6Wy/VI+NwXQ9RRnez+ADhvKwCgl/bwBWzvRvUVUvnOaEP +# 6SNJvBi4RHxF5MHDcnrgcuck379GmcXvwhxX24ON7E1JMKerjt/sW5+v/N2wZuLB +# l4F77dbtS+dJKacTKKanfWeA5opieF+yL4TXV5xcv3coKPHtbcMojyyPQDdPweGF +# RInECUzF1KVDL3SV9274eCBYLBNdYJWaPk8zhNqwiBfenk70lrC8RqBsmNLg1oiM +# CwIDAQABo4IB7TCCAekwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFEhuZOVQ +# BdOCqhc3NyK1bajKdQKVMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1Ud +# DwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFHItOgIxkEO5FAVO +# 4eqnxzHRI4k0MFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9jcmwubWljcm9zb2Z0 +# LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y +# Mi5jcmwwXgYIKwYBBQUHAQEEUjBQME4GCCsGAQUFBzAChkJodHRwOi8vd3d3Lm1p +# Y3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y +# Mi5jcnQwgZ8GA1UdIASBlzCBlDCBkQYJKwYBBAGCNy4DMIGDMD8GCCsGAQUFBwIB +# FjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2RvY3MvcHJpbWFyeWNw +# cy5odG0wQAYIKwYBBQUHAgIwNB4yIB0ATABlAGcAYQBsAF8AcABvAGwAaQBjAHkA +# XwBzAHQAYQB0AGUAbQBlAG4AdAAuIB0wDQYJKoZIhvcNAQELBQADggIBAGfyhqWY +# 4FR5Gi7T2HRnIpsLlhHhY5KZQpZ90nkMkMFlXy4sPvjDctFtg/6+P+gKyju/R6mj +# 82nbY78iNaWXXWWEkH2LRlBV2AySfNIaSxzzPEKLUtCw/WvjPgcuKZvmPRul1LUd +# d5Q54ulkyUQ9eHoj8xN9ppB0g430yyYCRirCihC7pKkFDJvtaPpoLpWgKj8qa1hJ +# Yx8JaW5amJbkg/TAj/NGK978O9C9Ne9uJa7lryft0N3zDq+ZKJeYTQ49C/IIidYf +# wzIY4vDFLc5bnrRJOQrGCsLGra7lstnbFYhRRVg4MnEnGn+x9Cf43iw6IGmYslmJ +# aG5vp7d0w0AFBqYBKig+gj8TTWYLwLNN9eGPfxxvFX1Fp3blQCplo8NdUmKGwx1j +# NpeG39rz+PIWoZon4c2ll9DuXWNB41sHnIc+BncG0QaxdR8UvmFhtfDcxhsEvt9B +# xw4o7t5lL+yX9qFcltgA1qFGvVnzl6UJS0gQmYAf0AApxbGbpT9Fdx41xtKiop96 +# eiL6SJUfq/tHI4D1nvi/a7dLl+LrdXga7Oo3mXkYS//WsyNodeav+vyL6wuA6mk7 +# r/ww7QRMjt/fdW1jkT3RnVZOT7+AVyKheBEyIXrvQQqxP/uozKRdwaGIm1dxVk5I +# RcBCyZt2WwqASGv9eZ/BvW1taslScxMNelDNMYIVZzCCFWMCAQEwgZUwfjELMAkG +# A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx +# HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9z +# b2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMQITMwAAAYdyF3IVWUDHCQAAAAABhzAN +# BglghkgBZQMEAgEFAKCBrjAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgor +# BgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgE/MRhWyu +# Zg+EA2WKcxYC31nHVCTE6guHppZppc70RtkwQgYKKwYBBAGCNwIBDDE0MDKgFIAS +# AE0AaQBjAHIAbwBzAG8AZgB0oRqAGGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbTAN +# BgkqhkiG9w0BAQEFAASCAQBvcYCjRDXUYEIz9j2j0r4GFI2Y3g/CoNxDDBaeQ+gV +# khO0fK0oLh18RbV271Mg6SF7X7+mXB5MnL68voVQDqHnsCYrIAuMF/AEpv9YuDDp +# ZRJuqN7Vwg3HM02l/FyATBIMgf/V79aYzJL3jjtt9bRIyxk6aPU4XcwMeA4usnUQ +# rMhIiQz07DgfSrcQWe4AvGFAIvqTAKE4P944EZWWVnWI/10rvatEAefqJZX3XljW +# sK/6NY/0MyAyiILOuXbvVS0YFbHaR2qd1jUXbrY79fS+H4Ts6qnbufOkHQvmcDxs +# 801wKLHumMdPTtMVzfVMCwPvrHP0wtzsFlmCcKjBbGpvoYIS8TCCEu0GCisGAQQB +# gjcDAwExghLdMIIS2QYJKoZIhvcNAQcCoIISyjCCEsYCAQMxDzANBglghkgBZQME +# AgEFADCCAVUGCyqGSIb3DQEJEAEEoIIBRASCAUAwggE8AgEBBgorBgEEAYRZCgMB +# MDEwDQYJYIZIAWUDBAIBBQAEINdeoXtuzW+Dihw6n+VdG+91si0f6TvWhJXaPtvW +# oF4cAgZfu+i3IT8YEzIwMjAxMjE3MDYzMDM2LjU0M1owBIACAfSggdSkgdEwgc4x +# CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt +# b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1p +# Y3Jvc29mdCBPcGVyYXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMg +# VFNTIEVTTjo4OTdBLUUzNTYtMTcwMTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUt +# U3RhbXAgU2VydmljZaCCDkQwggT1MIID3aADAgECAhMzAAABLCKvRZd1+RvuAAAA +# AAEsMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo +# aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y +# cG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEw +# MB4XDTE5MTIxOTAxMTUwM1oXDTIxMDMxNzAxMTUwM1owgc4xCzAJBgNVBAYTAlVT +# MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK +# ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVy +# YXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjo4OTdB +# LUUzNTYtMTcwMTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vydmlj +# ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPK1zgSSq+MxAYo3qpCt +# QDxSMPPJy6mm/wfEJNjNUnYtLFBwl1BUS5trEk/t41ldxITKehs+ABxYqo4Qxsg3 +# Gy1ugKiwHAnYiiekfC+ZhptNFgtnDZIn45zC0AlVr/6UfLtsLcHCh1XElLUHfEC0 +# nBuQcM/SpYo9e3l1qY5NdMgDGxCsmCKdiZfYXIu+U0UYIBhdzmSHnB3fxZOBVcr5 +# htFHEBBNt/rFJlm/A4yb8oBsp+Uf0p5QwmO/bCcdqB15JpylOhZmWs0sUfJKlK9E +# rAhBwGki2eIRFKsQBdkXS9PWpF1w2gIJRvSkDEaCf+lbGTPdSzHSbfREWOF9wY3i +# Yj8CAwEAAaOCARswggEXMB0GA1UdDgQWBBRRahZSGfrCQhCyIyGH9DkiaW7L0zAf +# BgNVHSMEGDAWgBTVYzpcijGQ80N7fEYbxTNoWoVtVTBWBgNVHR8ETzBNMEugSaBH +# hkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNU +# aW1TdGFQQ0FfMjAxMC0wNy0wMS5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUF +# BzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1RpbVN0 +# YVBDQV8yMDEwLTA3LTAxLmNydDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsG +# AQUFBwMIMA0GCSqGSIb3DQEBCwUAA4IBAQBPFxHIwi4vAH49w9Svmz6K3tM55RlW +# 5pPeULXdut2Rqy6Ys0+VpZsbuaEoxs6Z1C3hMbkiqZFxxyltxJpuHTyGTg61zfNI +# F5n6RsYF3s7IElDXNfZznF1/2iWc6uRPZK8rxxUJ/7emYXZCYwuUY0XjsCpP9pbR +# RKeJi6r5arSyI+NfKxvgoM21JNt1BcdlXuAecdd/k8UjxCscffanoK2n6LFw1PcZ +# lEO7NId7o+soM2C0QY5BYdghpn7uqopB6ixyFIIkDXFub+1E7GmAEwfU6VwEHL7y +# 9rNE8bd+JrQs+yAtkkHy9FmXg/PsGq1daVzX1So7CJ6nyphpuHSN3VfTMIIGcTCC +# BFmgAwIBAgIKYQmBKgAAAAAAAjANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMC +# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV +# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJv +# b3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTAwHhcNMTAwNzAxMjEzNjU1WhcN +# MjUwNzAxMjE0NjU1WjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv +# bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0 +# aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDCCASIw +# DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkdDbx3EYo6IOz8E5f1+n9plGt0 +# VBDVpQoAgoX77XxoSyxfxcPlYcJ2tz5mK1vwFVMnBDEfQRsalR3OCROOfGEwWbEw +# RA/xYIiEVEMM1024OAizQt2TrNZzMFcmgqNFDdDq9UeBzb8kYDJYYEbyWEeGMoQe +# dGFnkV+BVLHPk0ySwcSmXdFhE24oxhr5hoC732H8RsEnHSRnEnIaIYqvS2SJUGKx +# Xf13Hz3wV3WsvYpCTUBR0Q+cBj5nf/VmwAOWRH7v0Ev9buWayrGo8noqCjHw2k4G +# kbaICDXoeByw6ZnNPOcvRLqn9NxkvaQBwSAJk3jN/LzAyURdXhacAQVPIk0CAwEA +# AaOCAeYwggHiMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBTVYzpcijGQ80N7 +# fEYbxTNoWoVtVTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMC +# AYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvX +# zpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20v +# cGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYI +# KwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5j +# b20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDCBoAYDVR0g +# AQH/BIGVMIGSMIGPBgkrBgEEAYI3LgMwgYEwPQYIKwYBBQUHAgEWMWh0dHA6Ly93 +# d3cubWljcm9zb2Z0LmNvbS9QS0kvZG9jcy9DUFMvZGVmYXVsdC5odG0wQAYIKwYB +# BQUHAgIwNB4yIB0ATABlAGcAYQBsAF8AUABvAGwAaQBjAHkAXwBTAHQAYQB0AGUA +# bQBlAG4AdAAuIB0wDQYJKoZIhvcNAQELBQADggIBAAfmiFEN4sbgmD+BcQM9naOh +# IW+z66bM9TG+zwXiqf76V20ZMLPCxWbJat/15/B4vceoniXj+bzta1RXCCtRgkQS +# +7lTjMz0YBKKdsxAQEGb3FwX/1z5Xhc1mCRWS3TvQhDIr79/xn/yN31aPxzymXlK +# kVIArzgPF/UveYFl2am1a+THzvbKegBvSzBEJCI8z+0DpZaPWSm8tv0E4XCfMkon +# /VWvL/625Y4zu2JfmttXQOnxzplmkIz/amJ/3cVKC5Em4jnsGUpxY517IW3DnKOi +# PPp/fZZqkHimbdLhnPkd/DjYlPTGpQqWhqS9nhquBEKDuLWAmyI4ILUl5WTs9/S/ +# fmNZJQ96LjlXdqJxqgaKD4kWumGnEcua2A5HmoDF0M2n0O99g/DhO3EJ3110mCII +# YdqwUB5vvfHhAN/nMQekkzr3ZUd46PioSKv33nJ+YWtvd6mBy6cJrDm77MbL2IK0 +# cs0d9LiFAR6A+xuJKlQ5slvayA1VmXqHczsI5pgt6o3gMy4SKfXAL1QnIffIrE7a +# KLixqduWsqdCosnPGUFN4Ib5KpqjEWYw07t0MkvfY3v1mYovG8chr1m1rtxEPJdQ +# cdeh0sVV42neV8HR3jDA/czmTfsNv11P6Z0eGTgvvM9YBS7vDaBQNdrvCScc1bN+ +# NR4Iuto229Nfj950iEkSoYIC0jCCAjsCAQEwgfyhgdSkgdEwgc4xCzAJBgNVBAYT +# AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD +# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1pY3Jvc29mdCBP +# cGVyYXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjo4 +# OTdBLUUzNTYtMTcwMTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vy +# dmljZaIjCgEBMAcGBSsOAwIaAxUADE5OKSMoNx/mYxYWap1RTOohbJ2ggYMwgYCk +# fjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH +# UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQD +# Ex1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQUFAAIF +# AOOFYaowIhgPMjAyMDEyMTcwODQ4NDJaGA8yMDIwMTIxODA4NDg0MlowdzA9Bgor +# BgEEAYRZCgQBMS8wLTAKAgUA44VhqgIBADAKAgEAAgIoWgIB/zAHAgEAAgISJTAK +# AgUA44azKgIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIB +# AAIDB6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBBQUAA4GBAB53NDoDDF4vqFWY +# fwUnSvAy3z0CtqSFeA9RzDKGklPRwVkya5DtmVBDTZUbVQ2ST9hvRAVxhktfyVBZ +# ewapGJsvwMhg7nnEqBOumt6TvueIZpbs+p5z//3+iFYGkT3YFQI0Gd2JkvgBxfs5 +# +GptO6JKtiyA+zkKijxqXZvMqMxBMYIDDTCCAwkCAQEwgZMwfDELMAkGA1UEBhMC +# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV +# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp +# bWUtU3RhbXAgUENBIDIwMTACEzMAAAEsIq9Fl3X5G+4AAAAAASwwDQYJYIZIAWUD +# BAIBBQCgggFKMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0B +# CQQxIgQg3wEUtEvxwCp3aAFB2vGXOOqg/AXHyXZh9P9J+0uArDMwgfoGCyqGSIb3 +# DQEJEAIvMYHqMIHnMIHkMIG9BCBbn/0uFFh42hTM5XOoKdXevBaiSxmYK9Ilcn9n +# u5ZH4TCBmDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9u +# MRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp +# b24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAAB +# LCKvRZd1+RvuAAAAAAEsMCIEINBRtGID6jvA2ptfwIuPyG7qPcLRYb9YrJ8aKfVg +# TulFMA0GCSqGSIb3DQEBCwUABIIBACQQpFGWW6JmH5MTKwhaE/8+gyzI2bT8XJnA +# t8k7PHFvEGA7whgp9eNgW+wWJm1gnsmswjx2l7FW4DLg9lghM8FK77JRCg7CJfse +# dSbnTv81/4VhSXOAO0jMP2dALP7DF59vQmlDh50u8/Wu61ActMOt6cArkoUhBRXO +# LnqOQCOEEku5Xy2ES9g9eUfLUvTvlWo6HiAq+cJnNV08QRBOnGWRxdwy8YJ5vwNW +# Pwx0ZG3rTvMtGzOaW6Ve5O36H2ynoEdzCmpakeDaF2sZ86/LNERKyIXiykV/Uig1 +# SZh2VLY/Yni9SCVHbYgvTOCh5ZZE5eOi6BwLf0T4xl5alHUx+AA= +# SIG # End signature block From a039299376dd7d583b6eab547ba56582b1c35a0b Mon Sep 17 00:00:00 2001 From: vk Date: Sun, 28 Mar 2021 22:04:43 -0400 Subject: [PATCH 09/13] Upgrade Cake to v1.0, closes #241 --- build.ps1 | 235 --------------------------------------------- dotnet-install.ps1 | 101 +++++++++++-------- 2 files changed, 59 insertions(+), 277 deletions(-) delete mode 100644 build.ps1 diff --git a/build.ps1 b/build.ps1 deleted file mode 100644 index 82529cf60..000000000 --- a/build.ps1 +++ /dev/null @@ -1,235 +0,0 @@ -########################################################################## -# This is the Cake bootstrapper script for PowerShell. -# This file was downloaded from https://github.com/cake-build/resources -# Feel free to change this file to fit your needs. -########################################################################## - -<# - -.SYNOPSIS -This is a Powershell script to bootstrap a Cake build. - -.DESCRIPTION -This Powershell script will download NuGet if missing, restore NuGet tools (including Cake) -and execute your Cake build script with the parameters you provide. - -.PARAMETER Script -The build script to execute. -.PARAMETER Target -The build script target to run. -.PARAMETER Configuration -The build configuration to use. -.PARAMETER Verbosity -Specifies the amount of information to be displayed. -.PARAMETER ShowDescription -Shows description about tasks. -.PARAMETER DryRun -Performs a dry run. -.PARAMETER Experimental -Uses the nightly builds of the Roslyn script engine. -.PARAMETER Mono -Uses the Mono Compiler rather than the Roslyn script engine. -.PARAMETER SkipToolPackageRestore -Skips restoring of packages. -.PARAMETER ScriptArgs -Remaining arguments are added here. - -.LINK -https://cakebuild.net - -#> - -[CmdletBinding()] -Param( - [string]$Script = "build.cake", - [string]$Target, - [string]$Configuration, - [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")] - [string]$Verbosity, - [switch]$ShowDescription, - [Alias("WhatIf", "Noop")] - [switch]$DryRun, - [switch]$Experimental, - [switch]$Mono, - [switch]$SkipToolPackageRestore, - [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)] - [string[]]$ScriptArgs -) - -[Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null -function MD5HashFile([string] $filePath) -{ - if ([string]::IsNullOrEmpty($filePath) -or !(Test-Path $filePath -PathType Leaf)) - { - return $null - } - - [System.IO.Stream] $file = $null; - [System.Security.Cryptography.MD5] $md5 = $null; - try - { - $md5 = [System.Security.Cryptography.MD5]::Create() - $file = [System.IO.File]::OpenRead($filePath) - return [System.BitConverter]::ToString($md5.ComputeHash($file)) - } - finally - { - if ($file -ne $null) - { - $file.Dispose() - } - } -} - -function GetProxyEnabledWebClient -{ - $wc = New-Object System.Net.WebClient - $proxy = [System.Net.WebRequest]::GetSystemWebProxy() - $proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials - $wc.Proxy = $proxy - return $wc -} - -Write-Host "Preparing to run build script..." - -if(!$PSScriptRoot){ - $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent -} - -$TOOLS_DIR = Join-Path $PSScriptRoot "tools" -$ADDINS_DIR = Join-Path $TOOLS_DIR "Addins" -$MODULES_DIR = Join-Path $TOOLS_DIR "Modules" -$NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe" -$CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe" -$NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" -$PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config" -$PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum" -$ADDINS_PACKAGES_CONFIG = Join-Path $ADDINS_DIR "packages.config" -$MODULES_PACKAGES_CONFIG = Join-Path $MODULES_DIR "packages.config" - -# Make sure tools folder exists -if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) { - Write-Verbose -Message "Creating tools directory..." - New-Item -Path $TOOLS_DIR -Type directory | out-null -} - -# Make sure that packages.config exist. -if (!(Test-Path $PACKAGES_CONFIG)) { - Write-Verbose -Message "Downloading packages.config..." - try { - $wc = GetProxyEnabledWebClient - $wc.DownloadFile("https://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch { - Throw "Could not download packages.config." - } -} - -# Try find NuGet.exe in path if not exists -if (!(Test-Path $NUGET_EXE)) { - Write-Verbose -Message "Trying to find nuget.exe in PATH..." - $existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_ -PathType Container) } - $NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1 - if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) { - Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)." - $NUGET_EXE = $NUGET_EXE_IN_PATH.FullName - } -} - -# Try download NuGet.exe if not exists -if (!(Test-Path $NUGET_EXE)) { - Write-Verbose -Message "Downloading NuGet.exe..." - try { - $wc = GetProxyEnabledWebClient - $wc.DownloadFile($NUGET_URL, $NUGET_EXE) - } catch { - Throw "Could not download NuGet.exe." - } -} - -# Save nuget.exe path to environment to be available to child processed -$ENV:NUGET_EXE = $NUGET_EXE - -# Restore tools from NuGet? -if(-Not $SkipToolPackageRestore.IsPresent) { - Push-Location - Set-Location $TOOLS_DIR - - # Check for changes in packages.config and remove installed tools if true. - [string] $md5Hash = MD5HashFile($PACKAGES_CONFIG) - if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or - ($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) { - Write-Verbose -Message "Missing or changed package.config hash..." - Get-ChildItem -Exclude packages.config,nuget.exe,Cake.Bakery | - Remove-Item -Recurse - } - - Write-Verbose -Message "Restoring tools from NuGet..." - $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`"" - - if ($LASTEXITCODE -ne 0) { - Throw "An error occurred while restoring NuGet tools." - } - else - { - $md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII" - } - Write-Verbose -Message ($NuGetOutput | out-string) - - Pop-Location -} - -# Restore addins from NuGet -if (Test-Path $ADDINS_PACKAGES_CONFIG) { - Push-Location - Set-Location $ADDINS_DIR - - Write-Verbose -Message "Restoring addins from NuGet..." - $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$ADDINS_DIR`"" - - if ($LASTEXITCODE -ne 0) { - Throw "An error occurred while restoring NuGet addins." - } - - Write-Verbose -Message ($NuGetOutput | out-string) - - Pop-Location -} - -# Restore modules from NuGet -if (Test-Path $MODULES_PACKAGES_CONFIG) { - Push-Location - Set-Location $MODULES_DIR - - Write-Verbose -Message "Restoring modules from NuGet..." - $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$MODULES_DIR`"" - - if ($LASTEXITCODE -ne 0) { - Throw "An error occurred while restoring NuGet modules." - } - - Write-Verbose -Message ($NuGetOutput | out-string) - - Pop-Location -} - -# Make sure that Cake has been installed. -if (!(Test-Path $CAKE_EXE)) { - Throw "Could not find Cake.exe at $CAKE_EXE" -} - - - -# Build Cake arguments -$cakeArguments = @("$Script"); -if ($Target) { $cakeArguments += "-target=$Target" } -if ($Configuration) { $cakeArguments += "-configuration=$Configuration" } -if ($Verbosity) { $cakeArguments += "-verbosity=$Verbosity" } -if ($ShowDescription) { $cakeArguments += "-showdescription" } -if ($DryRun) { $cakeArguments += "-dryrun" } -if ($Experimental) { $cakeArguments += "-experimental" } -if ($Mono) { $cakeArguments += "-mono" } -$cakeArguments += $ScriptArgs - -# Start Cake -Write-Host "Running build script..." -&$CAKE_EXE $cakeArguments -exit $LASTEXITCODE diff --git a/dotnet-install.ps1 b/dotnet-install.ps1 index a502c8513..44828c9df 100644 --- a/dotnet-install.ps1 +++ b/dotnet-install.ps1 @@ -340,9 +340,8 @@ function Get-Latest-Version-Info([string]$AzureFeed, [string]$Channel) { elseif ($Runtime -eq "aspnetcore") { $VersionFileUrl = "$UncachedFeed/aspnetcore/Runtime/$Channel/latest.version" } - # Currently, the WindowsDesktop runtime is manufactured with the .Net core runtime elseif ($Runtime -eq "windowsdesktop") { - $VersionFileUrl = "$UncachedFeed/Runtime/$Channel/latest.version" + $VersionFileUrl = "$UncachedFeed/WindowsDesktop/$Channel/latest.version" } elseif (-not $Runtime) { $VersionFileUrl = "$UncachedFeed/Sdk/$Channel/latest.version" @@ -438,7 +437,16 @@ function Get-Download-Link([string]$AzureFeed, [string]$SpecificVersion, [string $PayloadURL = "$AzureFeed/aspnetcore/Runtime/$SpecificVersion/aspnetcore-runtime-$SpecificProductVersion-win-$CLIArchitecture.zip" } elseif ($Runtime -eq "windowsdesktop") { + # The windows desktop runtime is part of the core runtime layout prior to 5.0 $PayloadURL = "$AzureFeed/Runtime/$SpecificVersion/windowsdesktop-runtime-$SpecificProductVersion-win-$CLIArchitecture.zip" + if ($SpecificVersion -match '^(\d+)\.(.*)$') + { + $majorVersion = [int]$Matches[1] + if ($majorVersion -ge 5) + { + $PayloadURL = "$AzureFeed/WindowsDesktop/$SpecificVersion/windowsdesktop-runtime-$SpecificProductVersion-win-$CLIArchitecture.zip" + } + } } elseif (-not $Runtime) { $PayloadURL = "$AzureFeed/Sdk/$SpecificVersion/dotnet-sdk-$SpecificProductVersion-win-$CLIArchitecture.zip" @@ -480,7 +488,16 @@ function Get-Product-Version([string]$AzureFeed, [string]$SpecificVersion) { $ProductVersionTxtURL = "$AzureFeed/aspnetcore/Runtime/$SpecificVersion/productVersion.txt" } elseif ($Runtime -eq "windowsdesktop") { + # The windows desktop runtime is part of the core runtime layout prior to 5.0 $ProductVersionTxtURL = "$AzureFeed/Runtime/$SpecificVersion/productVersion.txt" + if ($SpecificVersion -match '^(\d+)\.(.*)') + { + $majorVersion = [int]$Matches[1] + if ($majorVersion -ge 5) + { + $ProductVersionTxtURL = "$AzureFeed/WindowsDesktop/$SpecificVersion/productVersion.txt" + } + } } elseif (-not $Runtime) { $ProductVersionTxtURL = "$AzureFeed/Sdk/$SpecificVersion/productVersion.txt" @@ -885,10 +902,10 @@ Say "Note that the script does not resolve dependencies during installation." Say "To check the list of dependencies, go to https://docs.microsoft.com/dotnet/core/install/windows#dependencies" Say "Installation finished" # SIG # Begin signature block -# MIIjkgYJKoZIhvcNAQcCoIIjgzCCI38CAQExDzANBglghkgBZQMEAgEFADB5Bgor +# MIIjjwYJKoZIhvcNAQcCoIIjgDCCI3wCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG -# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCD2c707qnCLOLIC -# n6Mu5Gr4+Xp68foyZlGlTycnycc5l6CCDYEwggX/MIID56ADAgECAhMzAAABh3IX +# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCNsnhcJvx/hXmM +# w8KjuvvIMDBFonhg9XJFc1QwfTyH4aCCDYEwggX/MIID56ADAgECAhMzAAABh3IX # chVZQMcJAAAAAAGHMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p @@ -960,29 +977,29 @@ Say "Installation finished" # xw4o7t5lL+yX9qFcltgA1qFGvVnzl6UJS0gQmYAf0AApxbGbpT9Fdx41xtKiop96 # eiL6SJUfq/tHI4D1nvi/a7dLl+LrdXga7Oo3mXkYS//WsyNodeav+vyL6wuA6mk7 # r/ww7QRMjt/fdW1jkT3RnVZOT7+AVyKheBEyIXrvQQqxP/uozKRdwaGIm1dxVk5I -# RcBCyZt2WwqASGv9eZ/BvW1taslScxMNelDNMYIVZzCCFWMCAQEwgZUwfjELMAkG +# RcBCyZt2WwqASGv9eZ/BvW1taslScxMNelDNMYIVZDCCFWACAQEwgZUwfjELMAkG # A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx # HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9z # b2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMQITMwAAAYdyF3IVWUDHCQAAAAABhzAN # BglghkgBZQMEAgEFAKCBrjAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgor -# BgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgE/MRhWyu -# Zg+EA2WKcxYC31nHVCTE6guHppZppc70RtkwQgYKKwYBBAGCNwIBDDE0MDKgFIAS +# BgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgpT/bxWwe +# aW0EinKMWCAzDXUjwXkIHldYzR6lw4/1Pc0wQgYKKwYBBAGCNwIBDDE0MDKgFIAS # AE0AaQBjAHIAbwBzAG8AZgB0oRqAGGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbTAN -# BgkqhkiG9w0BAQEFAASCAQBvcYCjRDXUYEIz9j2j0r4GFI2Y3g/CoNxDDBaeQ+gV -# khO0fK0oLh18RbV271Mg6SF7X7+mXB5MnL68voVQDqHnsCYrIAuMF/AEpv9YuDDp -# ZRJuqN7Vwg3HM02l/FyATBIMgf/V79aYzJL3jjtt9bRIyxk6aPU4XcwMeA4usnUQ -# rMhIiQz07DgfSrcQWe4AvGFAIvqTAKE4P944EZWWVnWI/10rvatEAefqJZX3XljW -# sK/6NY/0MyAyiILOuXbvVS0YFbHaR2qd1jUXbrY79fS+H4Ts6qnbufOkHQvmcDxs -# 801wKLHumMdPTtMVzfVMCwPvrHP0wtzsFlmCcKjBbGpvoYIS8TCCEu0GCisGAQQB -# gjcDAwExghLdMIIS2QYJKoZIhvcNAQcCoIISyjCCEsYCAQMxDzANBglghkgBZQME +# BgkqhkiG9w0BAQEFAASCAQCHd7sSQVq0YDg8QDx6/kLWn3s6jtvvIDCCgsO9spHM +# quPd4FPbG67DCsKDClekQs52qrtRO3Zo+JMnCw4j3bS+gZHzeJr2shbftOrpsFoD +# l7OPcUmtrqul9dkQCOp8t0MP3ls0n96/YyNy6lz4BAlTdkdDx957uAxalKaCIBzb +# R9QyppOKIfNFvwD4EI5KI6tpmSy/uH8SrRg7ZExAYZl6J6R18WkL7KHn649lPoAQ +# ujwrIXH10xOJops45ILGzKWQcHmCzLJGYapL4VHUuK+73nT+9ZROGHdk/PyvIcdw +# iERa+C06v305t3DA+CuHFy1tvyw7IFF6RVbLZPwxrJjToYIS7jCCEuoGCisGAQQB +# gjcDAwExghLaMIIS1gYJKoZIhvcNAQcCoIISxzCCEsMCAQMxDzANBglghkgBZQME # AgEFADCCAVUGCyqGSIb3DQEJEAEEoIIBRASCAUAwggE8AgEBBgorBgEEAYRZCgMB -# MDEwDQYJYIZIAWUDBAIBBQAEINdeoXtuzW+Dihw6n+VdG+91si0f6TvWhJXaPtvW -# oF4cAgZfu+i3IT8YEzIwMjAxMjE3MDYzMDM2LjU0M1owBIACAfSggdSkgdEwgc4x +# MDEwDQYJYIZIAWUDBAIBBQAEIOCaTmvM1AP0WaEVqzKaaCu/R+bTlR4kCrM/ZXsb +# /eNOAgZgGeLsMwsYEzIwMjEwMjAzMjExNzQ5LjU5MVowBIACAfSggdSkgdEwgc4x # CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt # b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1p # Y3Jvc29mdCBPcGVyYXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMg # VFNTIEVTTjo4OTdBLUUzNTYtMTcwMTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUt -# U3RhbXAgU2VydmljZaCCDkQwggT1MIID3aADAgECAhMzAAABLCKvRZd1+RvuAAAA +# U3RhbXAgU2VydmljZaCCDkEwggT1MIID3aADAgECAhMzAAABLCKvRZd1+RvuAAAA # AAEsMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo # aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y # cG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEw @@ -1043,7 +1060,7 @@ Say "Installation finished" # cs0d9LiFAR6A+xuJKlQ5slvayA1VmXqHczsI5pgt6o3gMy4SKfXAL1QnIffIrE7a # KLixqduWsqdCosnPGUFN4Ib5KpqjEWYw07t0MkvfY3v1mYovG8chr1m1rtxEPJdQ # cdeh0sVV42neV8HR3jDA/czmTfsNv11P6Z0eGTgvvM9YBS7vDaBQNdrvCScc1bN+ -# NR4Iuto229Nfj950iEkSoYIC0jCCAjsCAQEwgfyhgdSkgdEwgc4xCzAJBgNVBAYT +# NR4Iuto229Nfj950iEkSoYICzzCCAjgCAQEwgfyhgdSkgdEwgc4xCzAJBgNVBAYT # AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1pY3Jvc29mdCBP # cGVyYXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjo4 @@ -1052,27 +1069,27 @@ Say "Installation finished" # fjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH # UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQD # Ex1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQUFAAIF -# AOOFYaowIhgPMjAyMDEyMTcwODQ4NDJaGA8yMDIwMTIxODA4NDg0MlowdzA9Bgor -# BgEEAYRZCgQBMS8wLTAKAgUA44VhqgIBADAKAgEAAgIoWgIB/zAHAgEAAgISJTAK -# AgUA44azKgIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIB -# AAIDB6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBBQUAA4GBAB53NDoDDF4vqFWY -# fwUnSvAy3z0CtqSFeA9RzDKGklPRwVkya5DtmVBDTZUbVQ2ST9hvRAVxhktfyVBZ -# ewapGJsvwMhg7nnEqBOumt6TvueIZpbs+p5z//3+iFYGkT3YFQI0Gd2JkvgBxfs5 -# +GptO6JKtiyA+zkKijxqXZvMqMxBMYIDDTCCAwkCAQEwgZMwfDELMAkGA1UEBhMC -# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV -# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp -# bWUtU3RhbXAgUENBIDIwMTACEzMAAAEsIq9Fl3X5G+4AAAAAASwwDQYJYIZIAWUD -# BAIBBQCgggFKMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0B -# CQQxIgQg3wEUtEvxwCp3aAFB2vGXOOqg/AXHyXZh9P9J+0uArDMwgfoGCyqGSIb3 -# DQEJEAIvMYHqMIHnMIHkMIG9BCBbn/0uFFh42hTM5XOoKdXevBaiSxmYK9Ilcn9n -# u5ZH4TCBmDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9u -# MRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp -# b24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAAB -# LCKvRZd1+RvuAAAAAAEsMCIEINBRtGID6jvA2ptfwIuPyG7qPcLRYb9YrJ8aKfVg -# TulFMA0GCSqGSIb3DQEBCwUABIIBACQQpFGWW6JmH5MTKwhaE/8+gyzI2bT8XJnA -# t8k7PHFvEGA7whgp9eNgW+wWJm1gnsmswjx2l7FW4DLg9lghM8FK77JRCg7CJfse -# dSbnTv81/4VhSXOAO0jMP2dALP7DF59vQmlDh50u8/Wu61ActMOt6cArkoUhBRXO -# LnqOQCOEEku5Xy2ES9g9eUfLUvTvlWo6HiAq+cJnNV08QRBOnGWRxdwy8YJ5vwNW -# Pwx0ZG3rTvMtGzOaW6Ve5O36H2ynoEdzCmpakeDaF2sZ86/LNERKyIXiykV/Uig1 -# SZh2VLY/Yni9SCVHbYgvTOCh5ZZE5eOi6BwLf0T4xl5alHUx+AA= +# AOPFChkwIhgPMjAyMTAyMDMxNTQwMDlaGA8yMDIxMDIwNDE1NDAwOVowdDA6Bgor +# BgEEAYRZCgQBMSwwKjAKAgUA48UKGQIBADAHAgEAAgIXmDAHAgEAAgIRyTAKAgUA +# 48ZbmQIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIBAAID +# B6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBBQUAA4GBAHeeznL2n6HWCjHH94Fl +# hcdW6TEXzq4XNgp1Gx1W9F8gJ4x+SwoV7elJZkwgGffcpHomLvIY/VSuzsl1NgtJ +# TWM2UxoqSv58BBOrl4eGhH6kkg8Ucy2tdeK5T8cHa8pMkq2j9pFd2mRG/6VMk0dl +# Xz7Uy3Z6bZqkcABMyAfuAaGbMYIDDTCCAwkCAQEwgZMwfDELMAkGA1UEBhMCVVMx +# EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT +# FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUt +# U3RhbXAgUENBIDIwMTACEzMAAAEsIq9Fl3X5G+4AAAAAASwwDQYJYIZIAWUDBAIB +# BQCgggFKMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0BCQQx +# IgQg/QYv7yp+354WTjWUIsXWndTEzXjaYjqwYjcBxCJKjdUwgfoGCyqGSIb3DQEJ +# EAIvMYHqMIHnMIHkMIG9BCBbn/0uFFh42hTM5XOoKdXevBaiSxmYK9Ilcn9nu5ZH +# 4TCBmDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw +# DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x +# JjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAABLCKv +# RZd1+RvuAAAAAAEsMCIEIIfIM3YbzHswb/Kj/qq1l1cHA6QBl+gEXYanUNJomrpT +# MA0GCSqGSIb3DQEBCwUABIIBAAwdcXssUZGO7ho5+NHLjIxLtQk543aKGo+lrRMY +# Q9abE1h/AaaNJl0iGxX4IihNWyfovSfYL3L4eODUBAu68tWSxeceRfWNsb/ZZfUi +# v89hpLssI/Gf1BEgNMA4zCuIGQiC8okusVumEpAhhvCEbSiTTTtBdolTnU/CAKui +# oxaU3R9XkKh1F4oAM26+dJ1J2BLQXPs5afNvvedDsZWNQUPK1sFF3JRfzxiTrwBW +# EJRyflev9gyDoqCHzippgb+6+eti1WTkcA9Q49GIT11S6LOAVqkSC9N7Nqf8ksh8 +# ARdwT8jigpsm+mj7lrVU9upDkhVYhKeO8oiZq95Q53Zkteo= # SIG # End signature block From 48fbcefdde0e9ca88ca42cbb106540954e687037 Mon Sep 17 00:00:00 2001 From: Vitaliy K Date: Sun, 11 Apr 2021 16:37:25 -0400 Subject: [PATCH 10/13] Enable nullable reference types, closes #239 PR #242 --- Directory.Build.props | 10 ++- Docker/start-mssql.ps1 | 2 +- GitReleaseManager.yaml | 1 + .../Announcements/AnnouncementModel.cs | 4 +- .../Announcements/NewAnnouncement.cs | 4 +- .../Suteki.TardisBank.Api.csproj | 4 +- .../Src/Suteki.TardisBank.Domain/Account.cs | 2 +- .../Suteki.TardisBank.Domain/Announcement.cs | 4 +- .../Src/Suteki.TardisBank.Domain/Child.cs | 4 +- .../Src/Suteki.TardisBank.Domain/Message.cs | 4 +- .../Src/Suteki.TardisBank.Domain/Parent.cs | 8 +- .../PaymentSchedule.cs | 4 +- .../Suteki.TardisBank.Domain.csproj | 4 +- .../Suteki.TardisBank.Domain/Transaction.cs | 6 +- .../Src/Suteki.TardisBank.Domain/User.cs | 8 +- .../Suteki.TardisBank.Infrastructure.csproj | 5 +- .../Suteki.TardisBank.Tasks/IUserService.cs | 6 +- .../Suteki.TardisBank.Tasks.csproj | 5 +- .../Suteki.TardisBank.Tasks/UserService.cs | 10 +-- .../Functional/AnnouncementControllerTests.cs | 6 +- .../Model/PaymentSchedulingQueryTests.cs | 2 +- .../Suteki.TardisBank.Tests.csproj | 14 ++-- .../Controllers/AnnouncementsController.cs | 15 ++-- .../NHibernate.config | 2 +- .../Suteki.TardisBank.WebApi.csproj | 18 +++-- .../App/Stubs/TransactionManagerStub.cs | 8 +- .../App/TransactionAttribute.WebApi.csproj | 19 ++++- .../Tests/TransactionAttribute.Tests.csproj | 10 +-- .../Tests/UnitOfWorkAttributeOverrideTests.cs | 5 +- SharpArch.AutoLoad.DotSettings | 6 ++ Src/Common/NHibernate/TestDatabaseSetup.cs | 44 +++-------- .../DomainModel/BaseObject.cs | 23 +++--- .../DomainModel/BaseObjectEqualityComparer.cs | 6 +- Src/SharpArch.Domain/DomainModel/Entity.cs | 73 ++++++++++++++++--- Src/SharpArch.Domain/DomainModel/IEntity.cs | 7 +- .../DomainModel/ValueObject.cs | 14 ++-- .../ITypePropertyDescriptorCache.cs | 6 +- .../Reflection/TypePropertyDescriptor.cs | 21 +++--- .../Reflection/TypePropertyDescriptorCache.cs | 14 ++-- Src/SharpArch.Domain/SharpArch.Domain.csproj | 4 +- Src/SharpArch.Domain/Specifications/AdHoc.cs | 4 +- .../Specifications/ILinqSpecification.cs | 4 +- .../Specifications/QuerySpecification.cs | 2 +- .../QuerySpecificationExtensions.cs | 23 +++--- .../HasUniqueDomainSignatureAttribute.cs | 4 +- .../HasUniqueDomainSignatureAttributeBase.cs | 15 ++-- .../CodeBaseLocator.cs | 5 +- .../SharpArch.Infrastructure.csproj | 4 +- .../NHibernateRegistrationExtensions.cs | 6 +- ...nate.Extensions.DependencyInjection.csproj | 4 +- .../Repositories/INHibernateRepository.cs | 18 ++--- .../EntityDuplicateChecker.cs | 27 ++++--- .../FluentNHibernateExtensions.cs | 5 +- .../FluentNHibernate/GeneratorHelper.cs | 2 +- .../NHibernateRepositoryBase.cs | 8 +- .../NHibernateSessionFactoryBuilder.cs | 19 ++--- .../DataAnnotationsEventListener.cs | 10 +-- .../SharpArch.NHibernate.csproj | 4 +- .../Repositories/IRavenDbRepository.cs | 9 +-- Src/SharpArch.RavenDb/RavenDbRepository.cs | 10 +-- .../SharpArch.RavenDb.csproj | 4 +- Src/SharpArch.RavenDb/TransactionManager.cs | 36 ++++----- .../NHibernate/DatabaseRepositoryTestsBase.cs | 10 +-- .../NHibernate/RepositoryTestsBase.cs | 14 ++-- .../SharpArch.Testing.NUnit.csproj | 4 +- .../LiveDatabaseTests.cs | 9 ++- .../SharpArch.Testing.Xunit.NHibernate.csproj | 2 +- .../SetCultureAttribute.cs | 12 +-- .../SharpArch.Testing.Xunit.csproj | 2 +- .../Helpers/EntityIdSetter.cs | 4 +- .../SharpArch.Testing.csproj | 2 +- .../SharpArch.Web.AspNetCore.csproj | 10 +-- .../Transaction/ApplyTransactionFilterBase.cs | 10 +-- .../Transaction/AutoTransactionHandler.cs | 4 +- .../Transaction/TransactionAttribute.cs | 40 +++++++++- .../HasUniqieDomainSignatureTestsBase.cs | 2 +- .../NHibernateSessionFactoryBuilderTests.cs | 2 +- .../RepositoryTests.cs | 2 +- .../SharpArch.Tests.NHibernate.csproj | 8 +- .../HasUniqieDomainSignatureTestsBase.cs | 6 +- .../RepositoryTests.cs | 2 +- .../SharpArch.XunitTests.NHibernate.csproj | 8 +- .../HasUniqueEntitySignatureValidatorTests.cs | 8 +- .../BaseObjectEqualityComparerTests.cs | 8 +- .../DomainModel/EntityTests.cs | 44 +++++------ .../DomainModel/ValueObjectTests.cs | 8 +- .../SharpArch.Domain/TestEntities.cs | 34 ++++----- .../SharpArch.XunitTests.csproj | 6 +- VersionHistory.txt | 4 + 89 files changed, 479 insertions(+), 421 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 5007d5aaf..f5164ac54 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -3,7 +3,7 @@ Sharp Architecture Sharp Architecture Dev Team - netstandard2.0;netstandard2.1;net5 + netstandard2.0;netstandard2.1;net5.0 false false true @@ -11,12 +11,13 @@ portable 9.0 + enable false - netcoreapp2.1;netcoreapp3.1;net5 + netcoreapp2.1;netcoreapp3.1;net5.0 @@ -27,6 +28,11 @@ True + + + $(DefineConstants);NULLABLE_REFERENCE_TYPES + + BSD-3-Clause True diff --git a/Docker/start-mssql.ps1 b/Docker/start-mssql.ps1 index 840afecc8..7bf11ec79 100644 --- a/Docker/start-mssql.ps1 +++ b/Docker/start-mssql.ps1 @@ -1 +1 @@ -docker.exe run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=Password12!' -p 2433:1433 -d -v./mssql-data:/var/opt/mssql/data mcr.microsoft.com/mssql/server:2017-latest-ubuntu \ No newline at end of file +docker.exe run --name sharparch-sql -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=Password12!' -p 2433:1433 -d -v./mssql-data:/var/opt/mssql/data mcr.microsoft.com/mssql/server:2017-latest-ubuntu \ No newline at end of file diff --git a/GitReleaseManager.yaml b/GitReleaseManager.yaml index dafb6de4c..3bdf262e7 100644 --- a/GitReleaseManager.yaml +++ b/GitReleaseManager.yaml @@ -35,6 +35,7 @@ issue-labels-exclude: - question - ready - wontfix + - pull-request issue-labels-alias: - name: breaking-change diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Api/Announcements/AnnouncementModel.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Api/Announcements/AnnouncementModel.cs index 87ac60dba..4506fe5c9 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Api/Announcements/AnnouncementModel.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Api/Announcements/AnnouncementModel.cs @@ -19,7 +19,7 @@ public class AnnouncementSummary [Required] [JsonProperty("title")] - public string Title { get; set; } + public string Title { get; set; } = null!; } @@ -30,6 +30,6 @@ public class AnnouncementModel : AnnouncementSummary { [JsonProperty("content")] [Required] - public string Content { get; set; } + public string Content { get; set; } = null!; } } diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Api/Announcements/NewAnnouncement.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Api/Announcements/NewAnnouncement.cs index ba367093b..b6363bc26 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Api/Announcements/NewAnnouncement.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Api/Announcements/NewAnnouncement.cs @@ -13,10 +13,10 @@ public class NewAnnouncement [Required] [JsonProperty("title")] - public string Title { get; set; } + public string Title { get; set; } = null!; [JsonProperty("content")] [Required] - public string Content { get; set; } + public string Content { get; set; } = null!; } } diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Api/Suteki.TardisBank.Api.csproj b/Samples/TardisBank/Src/Suteki.TardisBank.Api/Suteki.TardisBank.Api.csproj index 3a7f5eeb5..d5427c189 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Api/Suteki.TardisBank.Api.csproj +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Api/Suteki.TardisBank.Api.csproj @@ -13,8 +13,8 @@ - - + + diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Account.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Account.cs index 4eaa1e1d5..b0f38f93b 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Account.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Account.cs @@ -27,7 +27,7 @@ public virtual decimal Balance public virtual IList PaymentSchedules { get; protected set; } - public virtual void AddTransaction(string description, decimal amount) + public virtual void AddTransaction(string? description, decimal amount) { this.Transactions.Add(new Transaction(description, amount, this)); diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Announcement.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Announcement.cs index 19b1c922a..659a8993d 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Announcement.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Announcement.cs @@ -11,10 +11,10 @@ public class Announcement: Entity public virtual DateTime Date { get; set; } [MaxLength(120)] - public virtual string Title { get; set; } + public virtual string Title { get; set; } = null!; [MaxLength(2000)] - public virtual string Content { get; set; } + public virtual string? Content { get; set; } public virtual DateTime LastModifiedUtc { get; set; } diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Child.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Child.cs index 0d7564395..635b96825 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Child.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Child.cs @@ -17,7 +17,7 @@ protected Child() } public virtual int ParentId { get; set; } - public virtual Account Account { get; set; } + public virtual Account Account { get; set; } = null!; public virtual void ReceivePayment(decimal amount, string description) { @@ -75,4 +75,4 @@ public override string[] GetRoles() return new[] { UserRoles.Child }; } } -} \ No newline at end of file +} diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Message.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Message.cs index 95428e467..42f13c4ef 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Message.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Message.cs @@ -24,9 +24,9 @@ public virtual void Read() } public virtual DateTime Date { get; protected set; } - public virtual string Text { get; protected set; } + public virtual string? Text { get; protected set; } - public virtual User User { get; set; } + public virtual User User { get; set; } = null!; public virtual bool HasBeenRead { get; protected set; } } diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Parent.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Parent.cs index 415f42c1e..4d45b2453 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Parent.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Parent.cs @@ -17,8 +17,10 @@ protected Parent() { } - public virtual IList Children { get; protected set; } - public virtual string ActivationKey { get; protected set; } + public virtual IList Children { get; protected set; } = null!; + + public virtual string ActivationKey { get; protected set; } = null!; + // should be called when parent is first created. public virtual Parent Initialise(IMediator mediator) { @@ -69,7 +71,7 @@ public virtual bool HasChild(int childId) public virtual void RemoveChild(int childId) { - Child childToRemove = this.Children.SingleOrDefault(x => x.Id == childId); + Child? childToRemove = this.Children.SingleOrDefault(x => x.Id == childId); if (childToRemove != null) { this.Children.Remove(childToRemove); diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/PaymentSchedule.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/PaymentSchedule.cs index 4cee6cc29..145bd7707 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/PaymentSchedule.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/PaymentSchedule.cs @@ -22,9 +22,9 @@ protected PaymentSchedule() public virtual DateTime NextRun { get; protected set; } public virtual Interval Interval { get; protected set; } public virtual decimal Amount { get; protected set; } - public virtual string Description { get; protected set; } + public virtual string? Description { get; protected set; } - public virtual Account Account { get; protected set; } + public virtual Account Account { get; protected set; } = null!; public virtual void CalculateNextRunDate() { diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Suteki.TardisBank.Domain.csproj b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Suteki.TardisBank.Domain.csproj index eb369f047..5a5f2151a 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Suteki.TardisBank.Domain.csproj +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Suteki.TardisBank.Domain.csproj @@ -5,9 +5,9 @@ - + - + diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Transaction.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Transaction.cs index d49c04013..6a72bfadd 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Transaction.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/Transaction.cs @@ -6,7 +6,7 @@ namespace Suteki.TardisBank.Domain public class Transaction : Entity { - public Transaction(string description, decimal amount, Account account) + public Transaction(string? description, decimal amount, Account account) { this.Description = description; this.Amount = amount; @@ -18,10 +18,10 @@ protected Transaction() { } - public virtual string Description { get; protected set; } + public virtual string? Description { get; protected set; } public virtual decimal Amount { get; protected set; } - public virtual Account Account { get; protected set; } + public virtual Account Account { get; protected set; } = null!; public virtual DateTime Date { get; protected set; } } diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/User.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/User.cs index f7cdd5602..09d67e78f 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Domain/User.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Domain/User.cs @@ -32,11 +32,11 @@ protected User() { } - public virtual string Name { get; protected set; } - public virtual string UserName { get; protected set; } - public virtual string Password { get; protected set; } + public virtual string Name { get; protected set; } = null!; + public virtual string UserName { get; protected set; } = null!; + public virtual string Password { get; protected set; } = null!; public virtual bool IsActive { get; protected set; } - public virtual IList Messages { get; protected set; } + public virtual IList Messages { get; protected set; } = null!; protected User(string name, string userName, string password) { diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Infrastructure/Suteki.TardisBank.Infrastructure.csproj b/Samples/TardisBank/Src/Suteki.TardisBank.Infrastructure/Suteki.TardisBank.Infrastructure.csproj index 1e91fb1a9..6a60e2878 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Infrastructure/Suteki.TardisBank.Infrastructure.csproj +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Infrastructure/Suteki.TardisBank.Infrastructure.csproj @@ -8,9 +8,8 @@ - - - + + diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Tasks/IUserService.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Tasks/IUserService.cs index 415ac6fac..57e660cea 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Tasks/IUserService.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Tasks/IUserService.cs @@ -7,10 +7,10 @@ namespace Suteki.TardisBank.Tasks public interface IUserService { - Task GetCurrentUser(CancellationToken cancellationToken = default); + Task GetCurrentUser(CancellationToken cancellationToken = default); Task GetUser(int userId, CancellationToken cancellationToken = default); - Task GetUserByUserName(string userName, CancellationToken cancellationToken = default); - Task GetUserByActivationKey(string activationKey, CancellationToken cancellationToken = default); + Task GetUserByUserName(string userName, CancellationToken cancellationToken = default); + Task GetUserByActivationKey(string activationKey, CancellationToken cancellationToken = default); Task SaveUser(User user, CancellationToken cancellationToken = default); Task DeleteUser(int userId, CancellationToken cancellationToken = default); diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Tasks/Suteki.TardisBank.Tasks.csproj b/Samples/TardisBank/Src/Suteki.TardisBank.Tasks/Suteki.TardisBank.Tasks.csproj index a54f5cc11..122ea0437 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Tasks/Suteki.TardisBank.Tasks.csproj +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Tasks/Suteki.TardisBank.Tasks.csproj @@ -5,10 +5,9 @@ - - + - + diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Tasks/UserService.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Tasks/UserService.cs index 6baca1736..e5eb14143 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Tasks/UserService.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Tasks/UserService.cs @@ -25,9 +25,9 @@ public UserService(IHttpContextService context, ILinqRepository par _userRepository = userRepository; } - public Task GetCurrentUser(CancellationToken cancellationToken) + public Task GetCurrentUser(CancellationToken cancellationToken) { - if (!_context.UserIsAuthenticated) return Task.FromResult(null); + if (!_context.UserIsAuthenticated) return Task.FromResult(null); return GetUserByUserName(_context.UserName, cancellationToken); } @@ -37,17 +37,17 @@ public Task GetUser(int userId, CancellationToken cancellationToken) return _userRepository.FindOneAsync(userId, cancellationToken); } - public Task GetUserByUserName(string userName, CancellationToken cancellationToken) + public Task GetUserByUserName(string userName, CancellationToken cancellationToken) { if (userName == null) { throw new ArgumentNullException(nameof(userName)); } - return _userRepository.FindAll().Where(u => u.UserName == userName).FirstOrDefaultAsync(cancellationToken); + return _userRepository.FindAll().Where(u => u.UserName == userName).FirstOrDefaultAsync(cancellationToken)!; } - public async Task GetUserByActivationKey(string activationKey, CancellationToken cancellationToken) + public async Task GetUserByActivationKey(string activationKey, CancellationToken cancellationToken) { if (activationKey == null) { diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Functional/AnnouncementControllerTests.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Functional/AnnouncementControllerTests.cs index ea675c436..36e07905a 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Functional/AnnouncementControllerTests.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Functional/AnnouncementControllerTests.cs @@ -13,9 +13,9 @@ public class AnnouncementControllerTests : IClassFixture, IDisposable { readonly TestServerSetup _setup; - Uri _newAnnouncementUri; + Uri? _newAnnouncementUri; - public AnnouncementControllerTests([NotNull] TestServerSetup setup) + public AnnouncementControllerTests(TestServerSetup setup) { _setup = setup ?? throw new ArgumentNullException(nameof(setup)); } @@ -47,7 +47,7 @@ public async Task CanSaveAnnouncement() var response = await _setup.Client.PostAsJsonAsync("announcements", newAnnouncement); response.EnsureSuccessStatusCode(); - _newAnnouncementUri = response.Headers.Location; + _newAnnouncementUri = response.Headers.Location!; var announcementResponse = await _setup.Client.GetAsync(_newAnnouncementUri); announcementResponse.EnsureSuccessStatusCode(); diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/PaymentSchedulingQueryTests.cs b/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/PaymentSchedulingQueryTests.cs index ab7820ea6..ded018961 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/PaymentSchedulingQueryTests.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Model/PaymentSchedulingQueryTests.cs @@ -15,7 +15,7 @@ namespace Suteki.TardisBank.Tests.Model public class PaymentSchedulingQueryTests : TransientDatabaseTests { - Parent _parent; + Parent _parent = null!; DateTime _someDate; diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Suteki.TardisBank.Tests.csproj b/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Suteki.TardisBank.Tests.csproj index 0dd9f5d6d..2b05354fb 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Suteki.TardisBank.Tests.csproj +++ b/Samples/TardisBank/Src/Suteki.TardisBank.Tests/Suteki.TardisBank.Tests.csproj @@ -4,13 +4,13 @@ - - - - + + + + + - @@ -28,8 +28,8 @@ - - + + diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.WebApi/Controllers/AnnouncementsController.cs b/Samples/TardisBank/Src/Suteki.TardisBank.WebApi/Controllers/AnnouncementsController.cs index d2e0379e4..3d70ca0fc 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.WebApi/Controllers/AnnouncementsController.cs +++ b/Samples/TardisBank/Src/Suteki.TardisBank.WebApi/Controllers/AnnouncementsController.cs @@ -1,4 +1,5 @@ -namespace Suteki.TardisBank.WebApi.Controllers +#pragma warning disable 1573 +namespace Suteki.TardisBank.WebApi.Controllers { using System; using System.Collections.Generic; @@ -24,19 +25,20 @@ public class AnnouncementsController : ControllerBase { readonly ILinqRepository _announcementRepository; #if NETCOREAPP3_1 || NET5_0 - [NotNull] readonly LinkGenerator _linkGenerator; + readonly LinkGenerator _linkGenerator; #endif - [NotNull] readonly IMapper _mapper; + readonly IMapper _mapper; /// /// Creates AnnouncementController. /// /// Announcements repository. - public AnnouncementsController([NotNull] ILinqRepository announcementRepository, + /// Mapper + public AnnouncementsController(ILinqRepository announcementRepository, #if NETCOREAPP3_1 || NET5_0 LinkGenerator linkGenerator, #endif - [NotNull] IMapper mapper) + IMapper mapper) { _announcementRepository = announcementRepository ?? throw new ArgumentNullException(nameof(announcementRepository)); #if NETCOREAPP3_1 || NET5_0 @@ -70,7 +72,8 @@ public async Task>> Get() public async Task> Get(int id) { var announcement = await _announcementRepository.GetAsync(id).ConfigureAwait(false); - return announcement != null ? _mapper.Map(announcement) : null; + if (announcement != null) return _mapper.Map(announcement); + return NotFound(new {id}); } [HttpPost] diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.WebApi/NHibernate.config b/Samples/TardisBank/Src/Suteki.TardisBank.WebApi/NHibernate.config index ec276802f..4a5b0ee89 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.WebApi/NHibernate.config +++ b/Samples/TardisBank/Src/Suteki.TardisBank.WebApi/NHibernate.config @@ -4,7 +4,7 @@ Data Source=localhost,2433;Initial Catalog=TardisBank;Integrated Security=False;User ID=sa;Password=Password12!;Application Name=Suteki.TardisBank; NHibernate.Dialect.MsSql2012Dialect NHibernate.Connection.DriverConnectionProvider - NHibernate.Driver.Sql2008ClientDriver + NHibernate.Driver.MicrosoftDataSqlClientDriver true auto 500 diff --git a/Samples/TardisBank/Src/Suteki.TardisBank.WebApi/Suteki.TardisBank.WebApi.csproj b/Samples/TardisBank/Src/Suteki.TardisBank.WebApi/Suteki.TardisBank.WebApi.csproj index 702a92e00..b32b62db3 100644 --- a/Samples/TardisBank/Src/Suteki.TardisBank.WebApi/Suteki.TardisBank.WebApi.csproj +++ b/Samples/TardisBank/Src/Suteki.TardisBank.WebApi/Suteki.TardisBank.WebApi.csproj @@ -8,28 +8,32 @@ - - - + + + - - + + + + - - + + + + diff --git a/Samples/TransactionAttribute/App/Stubs/TransactionManagerStub.cs b/Samples/TransactionAttribute/App/Stubs/TransactionManagerStub.cs index 776809c35..d65d55be0 100644 --- a/Samples/TransactionAttribute/App/Stubs/TransactionManagerStub.cs +++ b/Samples/TransactionAttribute/App/Stubs/TransactionManagerStub.cs @@ -16,9 +16,9 @@ public class TransactionManagerStub : ITransactionManager, IDisposable, ISupport public const string TransactionState = "x-transaction-result"; static readonly ILogger _log = Log.ForContext(); readonly IHttpContextAccessor _httpContextAccessor; - TransactionWrapper _transaction; + TransactionWrapper? _transaction; - public TransactionManagerStub([NotNull] IHttpContextAccessor httpContextAccessor) + public TransactionManagerStub(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor)); } @@ -38,7 +38,7 @@ public IDisposable BeginTransaction(IsolationLevel isolationLevel = IsolationLev public Task CommitTransactionAsync(CancellationToken cancellationToken) { - _httpContextAccessor.HttpContext.Response.Headers.Add(TransactionIsolationLevel, _transaction.IsolationLevel.ToString()); + _httpContextAccessor.HttpContext!.Response.Headers.Add(TransactionIsolationLevel, _transaction?.IsolationLevel.ToString() ?? "unknown"); _httpContextAccessor.HttpContext.Response.Headers.Add(TransactionState, "committed"); _transaction?.Commit(); return Task.CompletedTask; @@ -46,7 +46,7 @@ public Task CommitTransactionAsync(CancellationToken cancellationToken) public Task RollbackTransactionAsync(CancellationToken cancellationToken) { - _httpContextAccessor.HttpContext.Response.Headers.Add(TransactionIsolationLevel, _transaction.IsolationLevel.ToString()); + _httpContextAccessor.HttpContext!.Response.Headers.Add(TransactionIsolationLevel, _transaction?.IsolationLevel.ToString() ?? "unknown"); _httpContextAccessor.HttpContext.Response.Headers.Add(TransactionState, "rolled-back"); _transaction?.Dispose(); return Task.CompletedTask; diff --git a/Samples/TransactionAttribute/App/TransactionAttribute.WebApi.csproj b/Samples/TransactionAttribute/App/TransactionAttribute.WebApi.csproj index d37d0ff3d..bfefa8201 100644 --- a/Samples/TransactionAttribute/App/TransactionAttribute.WebApi.csproj +++ b/Samples/TransactionAttribute/App/TransactionAttribute.WebApi.csproj @@ -7,15 +7,28 @@ - - - + + + + + + + + + + + + + + + + diff --git a/Samples/TransactionAttribute/Tests/TransactionAttribute.Tests.csproj b/Samples/TransactionAttribute/Tests/TransactionAttribute.Tests.csproj index 89da09273..da7845a0e 100644 --- a/Samples/TransactionAttribute/Tests/TransactionAttribute.Tests.csproj +++ b/Samples/TransactionAttribute/Tests/TransactionAttribute.Tests.csproj @@ -7,9 +7,9 @@ - - - + + + all @@ -27,8 +27,8 @@ - - + + diff --git a/Samples/TransactionAttribute/Tests/UnitOfWorkAttributeOverrideTests.cs b/Samples/TransactionAttribute/Tests/UnitOfWorkAttributeOverrideTests.cs index 48a79fe98..c12a2da27 100644 --- a/Samples/TransactionAttribute/Tests/UnitOfWorkAttributeOverrideTests.cs +++ b/Samples/TransactionAttribute/Tests/UnitOfWorkAttributeOverrideTests.cs @@ -16,8 +16,9 @@ public class UnitOfWorkAttributeOverrideTests : IClassFixture { readonly TestServerSetup _setup; - public UnitOfWorkAttributeOverrideTests([NotNull] TestServerSetup setup) + public UnitOfWorkAttributeOverrideTests(TestServerSetup setup) { + if (setup == null) throw new ArgumentNullException(nameof(setup)); _setup = setup ?? throw new ArgumentNullException(nameof(setup)); } @@ -44,7 +45,7 @@ public async Task CanUseLocalOverride(string method, HttpStatusCode statusCode, Task GetAsync(string relativePath) { - return _setup.Client.GetAsync(new Uri(_setup.Client.BaseAddress, relativePath)); + return _setup.Client.GetAsync(new Uri(_setup.Client.BaseAddress!, relativePath)); } } } diff --git a/SharpArch.AutoLoad.DotSettings b/SharpArch.AutoLoad.DotSettings index 8dd6f407e..4a9b488b3 100644 --- a/SharpArch.AutoLoad.DotSettings +++ b/SharpArch.AutoLoad.DotSettings @@ -35,6 +35,7 @@ // $MESSAGE$ -- string literal in the form of "$NAME$ != null" FluentAssertions.AssertionExtensions.Should($EXPR$).NotBeNull() + CSharp90 True True LibLog.cs @@ -45,6 +46,7 @@ FluentAssertions.AssertionExtensions.Should($EXPR$).NotBeNull() DO_NOT_SHOW DO_NOT_SHOW DO_NOT_SHOW + DO_NOT_SHOW True True True @@ -424,8 +426,12 @@ FluentAssertions.AssertionExtensions.Should($EXPR$).NotBeNull() False ALWAYS True + True True True + True + + True True True diff --git a/Src/Common/NHibernate/TestDatabaseSetup.cs b/Src/Common/NHibernate/TestDatabaseSetup.cs index 4dd57282f..58ff1f875 100644 --- a/Src/Common/NHibernate/TestDatabaseSetup.cs +++ b/Src/Common/NHibernate/TestDatabaseSetup.cs @@ -5,8 +5,6 @@ using System.IO; using System.Linq; using System.Reflection; - using System.Threading; - using System.Threading.Tasks; using FluentNHibernate.Automapping; using global::NHibernate; using global::NHibernate.Cfg; @@ -27,10 +25,10 @@ [PublicAPI] public class TestDatabaseSetup : IDisposable { - [NotNull] readonly string _basePath; - [NotNull] readonly Assembly[] _mappingAssemblies; - [CanBeNull] Configuration _configuration; - [CanBeNull] ISessionFactory _sessionFactory; + readonly string _basePath; + readonly Assembly[] _mappingAssemblies; + Configuration? _configuration; + ISessionFactory? _sessionFactory; /// /// Initializes a new instance of the class. @@ -43,7 +41,7 @@ public class TestDatabaseSetup : IDisposable /// or is /// null. /// - public TestDatabaseSetup([NotNull] string basePath, [NotNull] Assembly[] mappingAssemblies) + public TestDatabaseSetup(string basePath, Assembly[] mappingAssemblies) { _basePath = basePath ?? throw new ArgumentNullException(nameof(basePath)); if (mappingAssemblies == null) throw new ArgumentNullException(nameof(mappingAssemblies)); @@ -62,7 +60,7 @@ public TestDatabaseSetup([NotNull] string basePath, [NotNull] Assembly[] mapping /// or is /// null. /// - public TestDatabaseSetup([NotNull] Assembly baseAssembly, [NotNull] Assembly[] mappingAssemblies) + public TestDatabaseSetup(Assembly baseAssembly, Assembly[] mappingAssemblies) : this(CodeBaseLocator.GetAssemblyCodeBasePath(baseAssembly), mappingAssemblies) { @@ -122,7 +120,7 @@ public static AutoPersistenceModel GenerateAutoPersistenceModel([NotNull] Assemb ["Assemblies"] = assemblies } }; - var generator = (IAutoPersistenceModelGenerator) Activator.CreateInstance(persistenceGeneratorTypes[0]); + var generator = (IAutoPersistenceModelGenerator) Activator.CreateInstance(persistenceGeneratorTypes[0])!; return generator.Generate(); } @@ -195,7 +193,7 @@ public ISession InitializeSession() /// Closes the specified session. /// /// The session. - public static void Close([CanBeNull] ISession session) + public static void Close(ISession? session) => session?.Dispose(); /// @@ -205,31 +203,7 @@ public static void Close([CanBeNull] ISession session) /// /// Dispose will destroy Session Factory associated with this instance. /// - public static void Shutdown([CanBeNull] ISessionFactory sessionFactory) + public static void Shutdown(ISessionFactory? sessionFactory) => sessionFactory?.Dispose(); - - ///// - ///// Loads the assembly. - ///// - ///// - ///// - //[NotNull] - //static Assembly TryLoadAssembly([NotNull] string assemblyPath) - // => Assembly.LoadFrom(assemblyPath); - - ///// - ///// Adds dll extension to assembly name if required. - ///// - ///// Name of the assembly. - ///// - //[NotNull] - //static string EnsureDllExtension([NotNull] string assemblyName) - //{ - // assemblyName = assemblyName.Trim(); - // const string dllExtension = ".dll"; - // if (!assemblyName.EndsWith(dllExtension, StringComparison.OrdinalIgnoreCase)) assemblyName = string.Concat(assemblyName, dllExtension); - - // return assemblyName; - //} } } diff --git a/Src/SharpArch.Domain/DomainModel/BaseObject.cs b/Src/SharpArch.Domain/DomainModel/BaseObject.cs index bd86b6d78..6b75b1587 100644 --- a/Src/SharpArch.Domain/DomainModel/BaseObject.cs +++ b/Src/SharpArch.Domain/DomainModel/BaseObject.cs @@ -3,7 +3,7 @@ using System; using System.Reflection; using JetBrains.Annotations; - using SharpArch.Domain.Reflection; + using Reflection; /// /// Provides a standard base class for facilitating comparison of objects. @@ -25,13 +25,13 @@ public abstract class BaseObject /// of collissions. See http://computinglife.wordpress.com/2008/11/20/why-do-hash-functions-use-prime-numbers/ /// for more information. /// - private const int HashMultiplier = 31; + const int HashMultiplier = 31; /// /// This static member caches the domain signature properties to avoid looking them up for /// each instance of the same type. /// - private static readonly ITypePropertyDescriptorCache signaturePropertiesCache + static readonly ITypePropertyDescriptorCache _signaturePropertiesCache = new TypePropertyDescriptorCache(); /// @@ -39,7 +39,7 @@ private static readonly ITypePropertyDescriptorCache signaturePropertiesCache /// /// The to compare with the current . /// true if the specified is equal to this instance; otherwise, false. - public override bool Equals(object obj) + public override bool Equals(object? obj) { var compareTo = obj as BaseObject; @@ -82,7 +82,7 @@ public override int GetHashCode() for (var i = 0; i < signatureProperties.Length; i++) { PropertyInfo property = signatureProperties[i]; - object value = property.GetValue(this, null); + object? value = property!.GetValue(this, null); if (value != null) { hashCode = (hashCode * HashMultiplier) ^ value.GetHashCode(); } @@ -100,13 +100,13 @@ public virtual PropertyInfo[] GetSignatureProperties() Type type = GetTypeUnproxied(); // Since data won't be in cache on first request only, use .GetOrAdd as second attempt to prevent allocation of extra lambda object. - TypePropertyDescriptor descriptor = signaturePropertiesCache.Find(type) ?? GetOrAdd(type); + TypePropertyDescriptor descriptor = _signaturePropertiesCache.Find(type) ?? GetOrAdd(type); return descriptor.Properties; } - private TypePropertyDescriptor GetOrAdd(Type type) + TypePropertyDescriptor GetOrAdd(Type type) { - return signaturePropertiesCache.GetOrAdd(type, + return _signaturePropertiesCache.GetOrAdd(type, t => new TypePropertyDescriptor(t, GetTypeSpecificSignatureProperties())); } @@ -134,15 +134,15 @@ public virtual bool HasSameObjectSignatureAs(BaseObject compareTo) // ReSharper disable once LoopCanBeConvertedToQuery for (var index = 0; index < signatureProperties.Length; index++) { PropertyInfo property = signatureProperties[index]; - object valueOfThisObject = property.GetValue(this, null); - object valueToCompareTo = property.GetValue(compareTo, null); + object? valueOfThisObject = property.GetValue(this, null); + object? valueToCompareTo = property.GetValue(compareTo, null); if (valueOfThisObject == null && valueToCompareTo == null) { continue; } if (valueOfThisObject == null ^ valueToCompareTo == null || - !valueOfThisObject.Equals(valueToCompareTo)) { + !(valueOfThisObject!.Equals(valueToCompareTo))) { return false; } } @@ -156,7 +156,6 @@ public virtual bool HasSameObjectSignatureAs(BaseObject compareTo) /// Enforces the template method pattern to have child objects determine which specific /// properties should and should not be included in the object signature comparison. /// - [NotNull] protected abstract PropertyInfo[] GetTypeSpecificSignatureProperties(); /// diff --git a/Src/SharpArch.Domain/DomainModel/BaseObjectEqualityComparer.cs b/Src/SharpArch.Domain/DomainModel/BaseObjectEqualityComparer.cs index 850902705..dc2696a40 100644 --- a/Src/SharpArch.Domain/DomainModel/BaseObjectEqualityComparer.cs +++ b/Src/SharpArch.Domain/DomainModel/BaseObjectEqualityComparer.cs @@ -28,7 +28,7 @@ public class BaseObjectEqualityComparer : IEqualityComparer /// The first object. /// The second object. /// true if the objects are equal, false otherwise. - public bool Equals([CanBeNull] T firstObject, [CanBeNull] T secondObject) + public bool Equals(T? firstObject, T? secondObject) { // While SQL would return false for the following condition, returning true when // comparing two null values is consistent with the C# language @@ -40,7 +40,7 @@ public bool Equals([CanBeNull] T firstObject, [CanBeNull] T secondObject) return false; } - return firstObject.Equals(secondObject); + return firstObject!.Equals(secondObject!); } /// Returns a hash code for the specified object. @@ -49,7 +49,7 @@ public bool Equals([CanBeNull] T firstObject, [CanBeNull] T secondObject) /// /// A hash code for the object, suitable for use in hashing algorithms and data structures like a hash table. /// - public int GetHashCode([NotNull] T obj) + public int GetHashCode(T obj) { if (obj == null) throw new ArgumentNullException(nameof(obj)); return obj.GetHashCode(); diff --git a/Src/SharpArch.Domain/DomainModel/Entity.cs b/Src/SharpArch.Domain/DomainModel/Entity.cs index 6b07131a3..e02d66e36 100644 --- a/Src/SharpArch.Domain/DomainModel/Entity.cs +++ b/Src/SharpArch.Domain/DomainModel/Entity.cs @@ -1,5 +1,9 @@ namespace SharpArch.Domain.DomainModel { +#if !NULLABLE_REFERENCE_TYPES + #pragma warning disable 8618 + #pragma warning disable 8604 +#endif using System; using System.Diagnostics.CodeAnalysis; using System.Linq; @@ -43,11 +47,21 @@ public abstract class Entity : ValidatableObject, IEntity, IEntity, /// /// [XmlIgnore] +#if NULLABLE_REFERENCE_TYPES + [AllowNull] [MaybeNull] +#endif public virtual TId Id { get; protected set; } + /// - public virtual object GetId() - => Id.Equals(default(TId)) ? (object)null : Id; + public virtual object? GetId() + { + // ReSharper disable once ConditionIsAlwaysTrueOrFalse + if (Id is null) return null; + return Id.Equals(default!) + ? (object?) null + : Id; + } /// /// Returns a value indicating whether the current object is transient. @@ -59,12 +73,13 @@ public virtual object GetId() /// public virtual bool IsTransient() { - if (!(Id is object)) return true; - return Id.Equals(default(TId)); + // ReSharper disable once ConditionIsAlwaysTrueOrFalse + return Id is null + || Id.Equals(default!); } /// - public virtual bool Equals(Entity other) + public virtual bool Equals(Entity? other) { if (ReferenceEquals(this, other)) { return true; @@ -74,7 +89,7 @@ public virtual bool Equals(Entity other) return false; } - if (HasSameNonDefaultIdAs(other)) { + if (HasSameNonDefaultIdAs(other!)) { return true; } @@ -90,7 +105,7 @@ public virtual bool Equals(Entity other) /// /// The to compare with the current . /// true if the specified is equal to this instance; otherwise, false. - public override bool Equals(object obj) + public override bool Equals(object? obj) { var compareTo = obj as Entity; return Equals(compareTo); @@ -108,7 +123,7 @@ public override bool Equals(object obj) /// if at all, in an object's lifetime, it's important that properties are carefully /// selected which truly represent the signature of an object. /// - [SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")] + [SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode", Justification = "By design")] public override int GetHashCode() { if (_cachedHashcode.HasValue) { @@ -119,12 +134,22 @@ public override int GetHashCode() _cachedHashcode = base.GetHashCode(); } else { - unchecked { + unchecked + { // It's possible for two objects to return the same hash code based on // identically valued properties, even if they're of two different types, // so we include the object's type in the hash calculation - int hashCode = GetType().GetHashCode(); - _cachedHashcode = (hashCode * HashMultiplier) ^ Id.GetHashCode(); + int hashCode = GetType().GetHashCode() * HashMultiplier; + + // ReSharper disable once ConditionIsAlwaysTrueOrFalse + if (Id is null) + { + _cachedHashcode = hashCode; + } + else + { + _cachedHashcode = hashCode ^ Id.GetHashCode(); + } } } @@ -158,7 +183,31 @@ protected override PropertyInfo[] GetTypeSpecificSignatureProperties() /// bool HasSameNonDefaultIdAs(Entity compareTo) { - return !IsTransient() && !compareTo.IsTransient() && Id.Equals(compareTo.Id); + return !IsTransient() && !compareTo.IsTransient() && Id!.Equals(compareTo.Id!); } + + /// + /// Check whether entities are equal. + /// + /// Entity to compare. + /// Entity to compare. + /// true if entities are equal, false otherwise. + public static bool operator ==(Entity? left, Entity? right) + => Equals(left, right); + + /// + /// Check whether entities are not equal. + /// + /// Entity to compare. + /// Entity to compare. + /// true if entities are not equal, false otherwise. + public static bool operator !=(Entity? left, Entity? right) + => !Equals(left, right); } + +#if !NULLABLE_REFERENCE_TYPES + #pragma warning restore 8618 + #pragma warning restore 8604 +#endif + } diff --git a/Src/SharpArch.Domain/DomainModel/IEntity.cs b/Src/SharpArch.Domain/DomainModel/IEntity.cs index 9259d3af0..8e148dd92 100644 --- a/Src/SharpArch.Domain/DomainModel/IEntity.cs +++ b/Src/SharpArch.Domain/DomainModel/IEntity.cs @@ -1,6 +1,7 @@ namespace SharpArch.Domain.DomainModel { using System; + using System.Diagnostics.CodeAnalysis; using System.Reflection; using JetBrains.Annotations; @@ -19,8 +20,7 @@ public interface IEntity /// Calling this method may result in boxing for entities with value type identifier. /// Use where possible. /// - [CanBeNull] - object GetId(); + object? GetId(); /// /// Returns the properties of the current object that make up the object's signature. @@ -69,6 +69,9 @@ public interface IEntity /// /// Gets the ID which uniquely identifies the entity instance within its type's bounds. /// +#if NULLABLE_REFERENCE_TYPES + [AllowNull] [MaybeNull] +#endif TId Id { get; } } diff --git a/Src/SharpArch.Domain/DomainModel/ValueObject.cs b/Src/SharpArch.Domain/DomainModel/ValueObject.cs index 168efb3fe..1ab9d9257 100644 --- a/Src/SharpArch.Domain/DomainModel/ValueObject.cs +++ b/Src/SharpArch.Domain/DomainModel/ValueObject.cs @@ -27,11 +27,10 @@ public abstract class ValueObject : BaseObject /// The first value object. /// The second value object. /// The result of the operator. - public static bool operator ==(ValueObject valueObject1, ValueObject valueObject2) + public static bool operator ==(ValueObject? valueObject1, ValueObject? valueObject2) { - if ((object) valueObject1 == null) { - return (object) valueObject2 == null; - } + if (ReferenceEquals(valueObject1, null)) + return ReferenceEquals(valueObject2, null); return valueObject1.Equals(valueObject2); } @@ -42,7 +41,7 @@ public abstract class ValueObject : BaseObject /// The first value object. /// The second value object. /// The result of the operator. - public static bool operator !=(ValueObject valueObject1, ValueObject valueObject2) + public static bool operator !=(ValueObject? valueObject1, ValueObject? valueObject2) { return !(valueObject1 == valueObject2); } @@ -52,7 +51,7 @@ public abstract class ValueObject : BaseObject /// /// The to compare with the current . /// true if the specified is equal to this instance; otherwise, false. - public override bool Equals(object obj) + public override bool Equals(object? obj) { return base.Equals(obj); } @@ -83,8 +82,7 @@ public override int GetHashCode() /// protected override PropertyInfo[] GetTypeSpecificSignatureProperties() { - var hasDomainSignature = this.GetType().GetProperties().Any(p => p.IsDefined(typeof(DomainSignatureAttribute), true)); - + var hasDomainSignature = GetType().GetProperties().Any(p => p.IsDefined(typeof(DomainSignatureAttribute), true)); if (hasDomainSignature) { string message = "Properties were found within " + GetType() + diff --git a/Src/SharpArch.Domain/Reflection/ITypePropertyDescriptorCache.cs b/Src/SharpArch.Domain/Reflection/ITypePropertyDescriptorCache.cs index e0144a89d..e2cccb522 100644 --- a/Src/SharpArch.Domain/Reflection/ITypePropertyDescriptorCache.cs +++ b/Src/SharpArch.Domain/Reflection/ITypePropertyDescriptorCache.cs @@ -22,8 +22,7 @@ public interface ITypePropertyDescriptorCache /// /// The type. /// or null if does not exists. - [CanBeNull] - TypePropertyDescriptor Find([NotNull] Type type); + TypePropertyDescriptor? Find(Type type); /// /// Get existing property descriptor or create and cache it. @@ -31,8 +30,7 @@ public interface ITypePropertyDescriptorCache /// The type. /// The factory to create descriptor. /// - [NotNull] - TypePropertyDescriptor GetOrAdd([NotNull] Type type, [NotNull] Func factory); + TypePropertyDescriptor GetOrAdd(Type type, Func factory); /// /// Clears the cache. diff --git a/Src/SharpArch.Domain/Reflection/TypePropertyDescriptor.cs b/Src/SharpArch.Domain/Reflection/TypePropertyDescriptor.cs index aba66f0a9..7f61ba4ec 100644 --- a/Src/SharpArch.Domain/Reflection/TypePropertyDescriptor.cs +++ b/Src/SharpArch.Domain/Reflection/TypePropertyDescriptor.cs @@ -11,8 +11,8 @@ namespace SharpArch.Domain.Reflection [PublicAPI] public class TypePropertyDescriptor : IEquatable { - private static readonly PropertyInfo[] emptyArray = Array.Empty(); - private readonly Type ownerType; + static readonly PropertyInfo[] _emptyArray = Array.Empty(); + readonly Type _ownerType; /// /// Initializes a new instance of the class. @@ -20,23 +20,22 @@ public class TypePropertyDescriptor : IEquatable /// Type of the object. /// The injectable properties. /// - public TypePropertyDescriptor([NotNull] Type ownerType, [CanBeNull] PropertyInfo[] properties) + public TypePropertyDescriptor(Type ownerType, PropertyInfo[]? properties) { if (ownerType == null) throw new ArgumentNullException(nameof(ownerType)); - this.ownerType = ownerType; + this._ownerType = ownerType; if (properties != null && properties.Length > 0) Properties = properties; else - Properties = emptyArray; + Properties = _emptyArray; } /// /// Owner type. /// - [NotNull] // ReSharper disable once ConvertToAutoPropertyWithPrivateSetter - public Type OwnerType => ownerType; + public Type OwnerType => _ownerType; /// /// Gets the injectable properties. @@ -44,7 +43,6 @@ public TypePropertyDescriptor([NotNull] Type ownerType, [CanBeNull] PropertyInfo /// /// The injectable properties. /// - [NotNull] public PropertyInfo[] Properties { get; private set; } /// @@ -54,7 +52,7 @@ public TypePropertyDescriptor([NotNull] Type ownerType, [CanBeNull] PropertyInfo /// /// true if the current object is equal to the parameter; otherwise, false. /// - public bool Equals(TypePropertyDescriptor other) + public bool Equals(TypePropertyDescriptor? other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; @@ -79,12 +77,11 @@ public bool HasProperties() /// /// true if the specified is equal to this instance; otherwise, false. /// - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - var other = obj as TypePropertyDescriptor; - return other != null && Equals(other); + return obj is TypePropertyDescriptor other && Equals(other); } /// diff --git a/Src/SharpArch.Domain/Reflection/TypePropertyDescriptorCache.cs b/Src/SharpArch.Domain/Reflection/TypePropertyDescriptorCache.cs index a2c0173ee..6a592ab39 100644 --- a/Src/SharpArch.Domain/Reflection/TypePropertyDescriptorCache.cs +++ b/Src/SharpArch.Domain/Reflection/TypePropertyDescriptorCache.cs @@ -11,8 +11,7 @@ [PublicAPI] public class TypePropertyDescriptorCache : ITypePropertyDescriptorCache { - private readonly ConcurrentDictionary cache = - new ConcurrentDictionary(); + readonly ConcurrentDictionary _cache = new(); /// /// Find cached property descriptor. @@ -22,10 +21,9 @@ public class TypePropertyDescriptorCache : ITypePropertyDescriptorCache /// or null if does not exists. /// [MustUseReturnValue] - public TypePropertyDescriptor Find(Type type) + public TypePropertyDescriptor? Find(Type type) { - TypePropertyDescriptor result; - cache.TryGetValue(type, out result); + _cache.TryGetValue(type, out TypePropertyDescriptor? result); return result; } @@ -44,7 +42,7 @@ public TypePropertyDescriptor GetOrAdd(Type type, Func @@ -52,12 +50,12 @@ public TypePropertyDescriptor GetOrAdd(Type type, Func public void Clear() { - cache.Clear(); + _cache.Clear(); } /// /// Returns number of entries in the cache. /// - public int Count => cache.Count; + public int Count => _cache.Count; } } diff --git a/Src/SharpArch.Domain/SharpArch.Domain.csproj b/Src/SharpArch.Domain/SharpArch.Domain.csproj index 824997797..76823944e 100644 --- a/Src/SharpArch.Domain/SharpArch.Domain.csproj +++ b/Src/SharpArch.Domain/SharpArch.Domain.csproj @@ -23,12 +23,12 @@ - + - + diff --git a/Src/SharpArch.Domain/Specifications/AdHoc.cs b/Src/SharpArch.Domain/Specifications/AdHoc.cs index 3e2c4bc1f..0672c0d62 100644 --- a/Src/SharpArch.Domain/Specifications/AdHoc.cs +++ b/Src/SharpArch.Domain/Specifications/AdHoc.cs @@ -15,7 +15,7 @@ public class AdHoc : QuerySpecification /// Initializes a new instance of the class. /// /// The expression. - public AdHoc([CanBeNull] Expression> expression) + public AdHoc(Expression>? expression) { MatchingCriteria = expression; } @@ -23,6 +23,6 @@ public AdHoc([CanBeNull] Expression> expression) /// /// Gets the matching criteria. /// - public override Expression> MatchingCriteria { get; } + public override Expression>? MatchingCriteria { get; } } } diff --git a/Src/SharpArch.Domain/Specifications/ILinqSpecification.cs b/Src/SharpArch.Domain/Specifications/ILinqSpecification.cs index 646ed2cdd..11aed5f4a 100644 --- a/Src/SharpArch.Domain/Specifications/ILinqSpecification.cs +++ b/Src/SharpArch.Domain/Specifications/ILinqSpecification.cs @@ -1,7 +1,6 @@ namespace SharpArch.Domain.Specifications { using System.Linq; - using JetBrains.Annotations; /// /// Defines a contract for the behaviour of a LINQ Specification design pattern. @@ -15,7 +14,6 @@ public interface ILinqSpecification /// /// The candidates. /// A list of satisfying elements. - [NotNull] - IQueryable SatisfyingElementsFrom([NotNull] IQueryable candidates); + IQueryable SatisfyingElementsFrom(IQueryable candidates); } } diff --git a/Src/SharpArch.Domain/Specifications/QuerySpecification.cs b/Src/SharpArch.Domain/Specifications/QuerySpecification.cs index b3f8f4cb2..08ce37309 100644 --- a/Src/SharpArch.Domain/Specifications/QuerySpecification.cs +++ b/Src/SharpArch.Domain/Specifications/QuerySpecification.cs @@ -15,7 +15,7 @@ public abstract class QuerySpecification : ILinqSpecification /// /// Gets the matching criteria. /// - public virtual Expression> MatchingCriteria => null; + public abstract Expression>? MatchingCriteria { get; } /// /// Returns the elements from the specified candidates that are satisfying the diff --git a/Src/SharpArch.Domain/Specifications/QuerySpecificationExtensions.cs b/Src/SharpArch.Domain/Specifications/QuerySpecificationExtensions.cs index 55ab1378d..a96a5901e 100644 --- a/Src/SharpArch.Domain/Specifications/QuerySpecificationExtensions.cs +++ b/Src/SharpArch.Domain/Specifications/QuerySpecificationExtensions.cs @@ -1,7 +1,6 @@ namespace SharpArch.Domain.Specifications { using System; - using System.Linq; using System.Linq.Expressions; using JetBrains.Annotations; @@ -22,14 +21,13 @@ public static class QuerySpecificationExtensions public static QuerySpecification And(this QuerySpecification specification1, QuerySpecification specification2) { - var adhocSpec1 = new AdHoc(specification1.MatchingCriteria); - var adhocSpec2 = new AdHoc(specification2.MatchingCriteria); - + if (specification1 == null) throw new ArgumentNullException(nameof(specification1)); + if (specification2 == null) throw new ArgumentNullException(nameof(specification2)); InvocationExpression invokedExpr = - Expression.Invoke(adhocSpec2.MatchingCriteria, adhocSpec1.MatchingCriteria.Parameters); + Expression.Invoke(specification2.MatchingCriteria!, specification1.MatchingCriteria!.Parameters); Expression> dynamicClause = Expression.Lambda>( - Expression.AndAlso(adhocSpec1.MatchingCriteria.Body, invokedExpr), - adhocSpec1.MatchingCriteria.Parameters); + Expression.AndAlso(specification1.MatchingCriteria!.Body, invokedExpr), + specification1.MatchingCriteria!.Parameters); return new AdHoc(dynamicClause); } @@ -45,14 +43,11 @@ public static QuerySpecification And(this QuerySpecification specificat public static QuerySpecification Or(this QuerySpecification specification1, QuerySpecification specification2) { - var adhocSpec1 = new AdHoc(specification1.MatchingCriteria); - var adhocSpec2 = new AdHoc(specification2.MatchingCriteria); - - InvocationExpression invokedExpr = Expression.Invoke(adhocSpec2.MatchingCriteria, - adhocSpec1.MatchingCriteria.Parameters.Cast()); + InvocationExpression invokedExpr = Expression.Invoke(specification2.MatchingCriteria!, + specification1.MatchingCriteria!.Parameters); Expression> dynamicClause = Expression.Lambda>( - Expression.OrElse(adhocSpec1.MatchingCriteria.Body, invokedExpr), - adhocSpec1.MatchingCriteria.Parameters); + Expression.OrElse(specification1.MatchingCriteria!.Body, invokedExpr), + specification1.MatchingCriteria!.Parameters); return new AdHoc(dynamicClause); } diff --git a/Src/SharpArch.Domain/Validation/HasUniqueDomainSignatureAttribute.cs b/Src/SharpArch.Domain/Validation/HasUniqueDomainSignatureAttribute.cs index 133667cec..716511931 100644 --- a/Src/SharpArch.Domain/Validation/HasUniqueDomainSignatureAttribute.cs +++ b/Src/SharpArch.Domain/Validation/HasUniqueDomainSignatureAttribute.cs @@ -3,7 +3,7 @@ using System; using System.ComponentModel.DataAnnotations; using JetBrains.Annotations; - using SharpArch.Domain.DomainModel; + using DomainModel; /// /// Provides a class level validator for determining if the entity has a unique domain signature @@ -24,7 +24,7 @@ public sealed class HasUniqueDomainSignatureAttribute : HasUniqueDomainSignature /// /// An instance of the class. /// - protected override ValidationResult IsValid(object value, ValidationContext validationContext) + protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) { return DoValidate(value, validationContext); } diff --git a/Src/SharpArch.Domain/Validation/HasUniqueDomainSignatureAttributeBase.cs b/Src/SharpArch.Domain/Validation/HasUniqueDomainSignatureAttributeBase.cs index a5e99d19a..89507eee5 100644 --- a/Src/SharpArch.Domain/Validation/HasUniqueDomainSignatureAttributeBase.cs +++ b/Src/SharpArch.Domain/Validation/HasUniqueDomainSignatureAttributeBase.cs @@ -4,8 +4,8 @@ namespace SharpArch.Domain.Validation using System.ComponentModel.DataAnnotations; using System.Globalization; using JetBrains.Annotations; - using SharpArch.Domain.DomainModel; - using SharpArch.Domain.PersistenceSupport; + using DomainModel; + using PersistenceSupport; /// /// Performs validation of domain signature uniqueness. @@ -42,20 +42,19 @@ protected HasUniqueDomainSignatureAttributeBase() /// can not be resolved from /// . /// - protected ValidationResult DoValidate([NotNull] object value, - [NotNull] ValidationContext validationContext) + protected ValidationResult? DoValidate(object? value, ValidationContext validationContext) { var entityToValidate = value as IEntity; if (entityToValidate == null) throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, - "This validator must be used at the class level of an " + nameof(IEntity) + ". The type you provided was {0}.", - value.GetType())); + "This validator must be used at the class level of an " + nameof(IEntity) + ". The type you provided was '{0}'.", + (value?.GetType() as object) ?? "null")); var duplicateChecker = - (IEntityDuplicateChecker) validationContext.GetService(typeof(IEntityDuplicateChecker)); + (IEntityDuplicateChecker?) validationContext.GetService(typeof(IEntityDuplicateChecker)); if (duplicateChecker == null) throw new InvalidOperationException( - $"'{typeof(IEntityDuplicateChecker).Name}' can not be resolved from validation context."); + $"'{nameof(IEntityDuplicateChecker)}' can not be resolved from validation context."); return duplicateChecker.DoesDuplicateExistWithTypedIdOf(entityToValidate) ? new ValidationResult(ErrorMessage) : ValidationResult.Success; diff --git a/Src/SharpArch.Infrastructure/CodeBaseLocator.cs b/Src/SharpArch.Infrastructure/CodeBaseLocator.cs index ae04c3fe8..09a2ef1c9 100644 --- a/Src/SharpArch.Infrastructure/CodeBaseLocator.cs +++ b/Src/SharpArch.Infrastructure/CodeBaseLocator.cs @@ -18,8 +18,7 @@ public class CodeBaseLocator /// Assembly /// Directory path /// is - [NotNull] - public static string GetAssemblyCodeBasePath([NotNull] Assembly assembly) + public static string GetAssemblyCodeBasePath(Assembly assembly) { if (assembly == null) throw new ArgumentNullException(nameof(assembly)); #if NET5_0 @@ -28,7 +27,7 @@ public static string GetAssemblyCodeBasePath([NotNull] Assembly assembly) var uri = new UriBuilder(assembly.CodeBase); #endif var uriPath = Uri.UnescapeDataString(uri.Path); - return Path.GetDirectoryName(uriPath); + return Path.GetDirectoryName(uriPath)!; } } } diff --git a/Src/SharpArch.Infrastructure/SharpArch.Infrastructure.csproj b/Src/SharpArch.Infrastructure/SharpArch.Infrastructure.csproj index 90eabbfe9..a9a6b0020 100644 --- a/Src/SharpArch.Infrastructure/SharpArch.Infrastructure.csproj +++ b/Src/SharpArch.Infrastructure/SharpArch.Infrastructure.csproj @@ -23,12 +23,12 @@ - + - + diff --git a/Src/SharpArch.NHibernate.DependencyInjection/NHibernateRegistrationExtensions.cs b/Src/SharpArch.NHibernate.DependencyInjection/NHibernateRegistrationExtensions.cs index e97a25438..8a1cbce08 100644 --- a/Src/SharpArch.NHibernate.DependencyInjection/NHibernateRegistrationExtensions.cs +++ b/Src/SharpArch.NHibernate.DependencyInjection/NHibernateRegistrationExtensions.cs @@ -45,9 +45,9 @@ public static class NHibernateRegistrationExtensions /// /// public static IServiceCollection AddNHibernateWithSingleDatabase( - [NotNull] this IServiceCollection services, [NotNull] Func configureSessionFactory, - [CanBeNull] Func sessionConfigurator = null, - [CanBeNull] Func statelessSessionConfigurator = null + this IServiceCollection services, Func configureSessionFactory, + Func? sessionConfigurator = null, + Func? statelessSessionConfigurator = null ) { if (services == null) throw new ArgumentNullException(nameof(services)); diff --git a/Src/SharpArch.NHibernate.DependencyInjection/SharpArch.NHibernate.Extensions.DependencyInjection.csproj b/Src/SharpArch.NHibernate.DependencyInjection/SharpArch.NHibernate.Extensions.DependencyInjection.csproj index 40d12dc75..5b350b769 100644 --- a/Src/SharpArch.NHibernate.DependencyInjection/SharpArch.NHibernate.Extensions.DependencyInjection.csproj +++ b/Src/SharpArch.NHibernate.DependencyInjection/SharpArch.NHibernate.Extensions.DependencyInjection.csproj @@ -16,7 +16,7 @@ - + @@ -28,7 +28,7 @@ - + diff --git a/Src/SharpArch.NHibernate/Contracts/Repositories/INHibernateRepository.cs b/Src/SharpArch.NHibernate/Contracts/Repositories/INHibernateRepository.cs index 9b45711f6..ca292c8a6 100644 --- a/Src/SharpArch.NHibernate/Contracts/Repositories/INHibernateRepository.cs +++ b/Src/SharpArch.NHibernate/Contracts/Repositories/INHibernateRepository.cs @@ -53,8 +53,7 @@ Task> FindAllAsync( /// Looks for a single instance using the example provided. /// /// - [ItemCanBeNull] - Task FindOneAsync(TEntity exampleInstance, CancellationToken cancellationToken, params string[] propertiesToExclude); + Task FindOneAsync(TEntity exampleInstance, CancellationToken cancellationToken, params string[] propertiesToExclude); /// /// Looks for a single instance using the property/values provided. @@ -62,9 +61,7 @@ Task> FindAllAsync( /// /// Property name/value pairs to use as search criteria. /// Cancellation token. - [ItemCanBeNull] - Task FindOneAsync( - IReadOnlyDictionary propertyValuePairs, CancellationToken cancellationToken = default); + Task FindOneAsync(IReadOnlyDictionary propertyValuePairs, CancellationToken cancellationToken = default); /// /// Returns null if a row is not found matching the provided Id. @@ -72,15 +69,13 @@ Task FindOneAsync( /// Entity identifier. /// Row Lock mode. /// Cancellation token. - [ItemCanBeNull] - Task GetAsync(TId id, Enums.LockMode lockMode, CancellationToken cancellationToken = default); + Task GetAsync(TId id, Enums.LockMode lockMode, CancellationToken cancellationToken = default); /// /// Return the persistent instance of the given entity class with the given identifier. /// /// Entity identifier. /// Cancellation token. - [ItemNotNull] Task LoadAsync(TId id, CancellationToken cancellationToken = default); /// @@ -90,7 +85,6 @@ Task FindOneAsync( /// Entity identifier. /// Row Lock mode. /// Cancellation token. - [ItemNotNull] Task LoadAsync(TId id, Enums.LockMode lockMode, CancellationToken cancellationToken = default); /// @@ -109,8 +103,7 @@ Task FindOneAsync( /// a detached instance with state to be copied /// Cancellation token. /// An updated persistent instance. - [ItemNotNull] - Task MergeAsync([NotNull] TEntity entity, CancellationToken cancellationToken = default); + Task MergeAsync(TEntity entity, CancellationToken cancellationToken = default); /// /// For entities that have assigned Id's, you should explicitly call Update to update an existing one. @@ -121,7 +114,6 @@ Task FindOneAsync( /// Cancellation token. /// Entity instance. /// is null. - [ItemNotNull] - Task UpdateAsync([NotNull] TEntity entity, CancellationToken cancellationToken = default); + Task UpdateAsync(TEntity entity, CancellationToken cancellationToken = default); } } diff --git a/Src/SharpArch.NHibernate/EntityDuplicateChecker.cs b/Src/SharpArch.NHibernate/EntityDuplicateChecker.cs index b401e007e..366ceb5b1 100644 --- a/Src/SharpArch.NHibernate/EntityDuplicateChecker.cs +++ b/Src/SharpArch.NHibernate/EntityDuplicateChecker.cs @@ -19,7 +19,7 @@ [PublicAPI] public class EntityDuplicateChecker : IEntityDuplicateChecker { - static readonly DateTime uninitializedDatetime = default(DateTime); + static readonly DateTime _uninitializedDatetime = default; readonly ISession _session; /// @@ -27,7 +27,7 @@ public class EntityDuplicateChecker : IEntityDuplicateChecker /// /// The session. /// - public EntityDuplicateChecker([NotNull] ISession session) + public EntityDuplicateChecker(ISession session) { _session = session ?? throw new ArgumentNullException(nameof(session)); } @@ -68,16 +68,16 @@ public bool DoesDuplicateExistWithTypedIdOf(IEntity entity) } static void AppendEntityIdCriteriaTo( - ICriteria criteria, string propertyName, object propertyValue) + ICriteria criteria, string propertyName, object? propertyValue) { criteria.Add( propertyValue != null - ? Restrictions.Eq(propertyName + ".id", ((IEntity) propertyValue).GetId()) + ? Restrictions.Eq(propertyName + ".id", ((IEntity) propertyValue).GetId()!) : Restrictions.IsNull(propertyName + ".id")); } static void AppendStringPropertyCriteriaTo( - ICriteria criteria, string propertyName, object propertyValue) + ICriteria criteria, string propertyName, object? propertyValue) { criteria.Add( propertyValue != null @@ -86,7 +86,7 @@ static void AppendStringPropertyCriteriaTo( } static void AppendValuePropertyCriteriaTo( - ICriteria criteria, string propertyName, object propertyValue) + ICriteria criteria, string propertyName, object? propertyValue) { criteria.Add( propertyValue != null @@ -94,7 +94,6 @@ static void AppendValuePropertyCriteriaTo( : Restrictions.IsNull(propertyName)); } - [NotNull] ISession GetSessionFor(object entity) { return _session; @@ -113,10 +112,10 @@ static string GetPropertyName(string parentPropertyName, PropertyInfo signatureP return string.Concat(parentPropertyName, signatureProperty.Name); } - static void AppendDateTimePropertyCriteriaTo(ICriteria criteria, string propertyName, object propertyValue) + static void AppendDateTimePropertyCriteriaTo(ICriteria criteria, string propertyName, object? propertyValue) { criteria.Add( - (DateTime) propertyValue > uninitializedDatetime + (propertyValue is null) || (DateTime) propertyValue > _uninitializedDatetime ? Restrictions.Eq(propertyName, propertyValue) : Restrictions.IsNull(propertyName)); } @@ -144,7 +143,7 @@ static void AppendSignaturePropertyCriteriaTo(ICriteria criteria, IEntity entity } static void AppendValueObjectSignaturePropertyCriteriaTo(ICriteria criteria, Type entityType, - string valueObjectPropertyName, ValueObject valueObject) + string valueObjectPropertyName, ValueObject? valueObject) { if (valueObject == null) { return; @@ -152,7 +151,7 @@ static void AppendValueObjectSignaturePropertyCriteriaTo(ICriteria criteria, Typ foreach (PropertyInfo signatureProperty in valueObject.GetSignatureProperties()) { Type propertyType = signatureProperty.PropertyType; - object propertyValue = signatureProperty.GetValue(valueObject, null); + object? propertyValue = signatureProperty.GetValue(valueObject, null); string propertyName = GetPropertyName(valueObjectPropertyName, signatureProperty); AppendSimplePropertyCriteriaTo(criteria, entityType, propertyValue, propertyType, propertyName); @@ -160,10 +159,10 @@ static void AppendValueObjectSignaturePropertyCriteriaTo(ICriteria criteria, Typ } static void AppendSimplePropertyCriteriaTo( - ICriteria criteria, Type entityType, object propertyValue, Type propertyType, string propertyName) + ICriteria criteria, Type entityType, object? propertyValue, Type propertyType, string propertyName) { if (propertyType.IsEnum) { - criteria.Add(Restrictions.Eq(propertyName, (int) propertyValue)); + criteria.Add(Restrictions.Eq(propertyName, (int) propertyValue!)); } else if (propertyType == typeof(DateTime)) { AppendDateTimePropertyCriteriaTo(criteria, propertyName, propertyValue); @@ -175,7 +174,7 @@ static void AppendSimplePropertyCriteriaTo( AppendValuePropertyCriteriaTo(criteria, propertyName, propertyValue); } else { - throw new ApplicationException( + throw new InvalidOperationException( "Can't determine how to use " + entityType + "." + propertyName + " when looking for duplicate entries. To remedy this, " + "you can create a custom validator or report an issue to the S#arp Architecture " diff --git a/Src/SharpArch.NHibernate/FluentNHibernate/FluentNHibernateExtensions.cs b/Src/SharpArch.NHibernate/FluentNHibernate/FluentNHibernateExtensions.cs index 74059697a..a996f59aa 100644 --- a/Src/SharpArch.NHibernate/FluentNHibernate/FluentNHibernateExtensions.cs +++ b/Src/SharpArch.NHibernate/FluentNHibernate/FluentNHibernateExtensions.cs @@ -27,11 +27,10 @@ public static class FluentNHibernateExtensions /// Mappings container /// Container /// is null. - public static FluentMappingsContainer AddFromNamespaceOf( - [NotNull] this FluentMappingsContainer mappingsContainer) + public static FluentMappingsContainer AddFromNamespaceOf(this FluentMappingsContainer mappingsContainer) { if (mappingsContainer == null) throw new ArgumentNullException(nameof(mappingsContainer)); - string ns = typeof(T).Namespace; + string ns = typeof(T).Namespace!; var types = typeof(T).Assembly.GetTypes() .Where(t => !t.IsAbstract && t.Namespace == ns) .Where(x => IsMappingOf(x) || diff --git a/Src/SharpArch.NHibernate/FluentNHibernate/GeneratorHelper.cs b/Src/SharpArch.NHibernate/FluentNHibernate/GeneratorHelper.cs index 8817893a7..8bf0c991f 100644 --- a/Src/SharpArch.NHibernate/FluentNHibernate/GeneratorHelper.cs +++ b/Src/SharpArch.NHibernate/FluentNHibernate/GeneratorHelper.cs @@ -23,7 +23,7 @@ public class GeneratorHelper /// public static IMapGenerator[] GetMapGenerators() { - var assembly = Assembly.GetAssembly(typeof(IMapGenerator)); + var assembly = typeof(IMapGenerator).Assembly; return (from type in assembly.GetTypes() where null != type.GetInterface(GeneratorInterface) diff --git a/Src/SharpArch.NHibernate/NHibernateRepositoryBase.cs b/Src/SharpArch.NHibernate/NHibernateRepositoryBase.cs index 4abd2f8c9..81419bf94 100644 --- a/Src/SharpArch.NHibernate/NHibernateRepositoryBase.cs +++ b/Src/SharpArch.NHibernate/NHibernateRepositoryBase.cs @@ -130,7 +130,7 @@ public Task> FindAllAsync( } /// - public virtual async Task FindOneAsync(TEntity exampleInstance, CancellationToken ct, params string[] propertiesToExclude) + public virtual async Task FindOneAsync(TEntity exampleInstance, CancellationToken ct, params string[] propertiesToExclude) { IList foundList = await FindAllAsync(exampleInstance, propertiesToExclude, 2, ct).ConfigureAwait(false); if (foundList.Count > 1) throw new NonUniqueResultException(foundList.Count); @@ -139,7 +139,7 @@ public virtual async Task FindOneAsync(TEntity exampleInstance, Cancell } /// - public async Task FindOneAsync( + public async Task FindOneAsync( IReadOnlyDictionary propertyValuePairs, CancellationToken cancellationToken = default) { @@ -150,8 +150,8 @@ public async Task FindOneAsync( } /// - public virtual Task GetAsync(TId id, Enums.LockMode lockMode, CancellationToken ct) - => Session.GetAsync(id, ConvertFrom(lockMode), ct); + public virtual Task GetAsync(TId id, Enums.LockMode lockMode, CancellationToken ct) + => Session.GetAsync(id, ConvertFrom(lockMode), ct); /// public virtual Task LoadAsync(TId id, CancellationToken ct) diff --git a/Src/SharpArch.NHibernate/NHibernateSessionFactoryBuilder.cs b/Src/SharpArch.NHibernate/NHibernateSessionFactoryBuilder.cs index da4ae0ade..ea2beb693 100644 --- a/Src/SharpArch.NHibernate/NHibernateSessionFactoryBuilder.cs +++ b/Src/SharpArch.NHibernate/NHibernateSessionFactoryBuilder.cs @@ -31,18 +31,18 @@ public class NHibernateSessionFactoryBuilder /// /// Default NHibernate session factory key. /// - [NotNull] public static readonly string DefaultConfigurationName = "nhibernate.current_session"; + public static readonly string DefaultConfigurationName = "nhibernate.current_session"; readonly List _mappingAssemblies; - AutoPersistenceModel _autoPersistenceModel; - string _configFile; + AutoPersistenceModel? _autoPersistenceModel; + string? _configFile; - Action _exposeConfiguration; - IPersistenceConfigurer _persistenceConfigurer; - IDictionary _properties; + Action? _exposeConfiguration; + IPersistenceConfigurer? _persistenceConfigurer; + IDictionary? _properties; bool _useDataAnnotationValidators; - Action _cacheSettingsBuilder; + Action? _cacheSettingsBuilder; /// /// Initializes a new instance of the class. @@ -56,7 +56,6 @@ public NHibernateSessionFactoryBuilder() /// Creates the session factory. /// /// NHibernate session factory . - [NotNull] public ISessionFactory BuildSessionFactory() { var configuration = BuildConfiguration(); @@ -67,7 +66,6 @@ public ISessionFactory BuildSessionFactory() /// Builds NHibernate configuration. /// /// No dependencies were specified - [NotNull] public Configuration BuildConfiguration() { var configuration = LoadExternalConfiguration(); @@ -83,7 +81,6 @@ public Configuration BuildConfiguration() /// Changes to configuration will be persisted in configuration cache, if it is enabled. /// In case changes must not be persisted in cache, they must be applied after . /// - [NotNull] public NHibernateSessionFactoryBuilder ExposeConfiguration([NotNull] Action config) { _exposeConfiguration = config ?? throw new ArgumentNullException(nameof(config)); @@ -259,7 +256,7 @@ void AddValidatorsAndExposeConfiguration(Configuration e) if (ShouldExposeConfiguration()) { - _exposeConfiguration(e); + _exposeConfiguration!(e); } } diff --git a/Src/SharpArch.NHibernate/NHibernateValidator/DataAnnotationsEventListener.cs b/Src/SharpArch.NHibernate/NHibernateValidator/DataAnnotationsEventListener.cs index cd389b497..2b8c760da 100644 --- a/Src/SharpArch.NHibernate/NHibernateValidator/DataAnnotationsEventListener.cs +++ b/Src/SharpArch.NHibernate/NHibernateValidator/DataAnnotationsEventListener.cs @@ -19,18 +19,18 @@ internal class DataAnnotationsEventListener : IPreUpdateEventListener, IPreInser class SessionProvider : IServiceProvider { - private readonly ISession session; + readonly ISession _session; public SessionProvider(ISession session) { - this.session = session; + _session = session; } - public object GetService(Type serviceType) + public object? GetService(Type serviceType) { if (serviceType == typeof (ISession)) { - return session; + return _session; } return null; } @@ -52,7 +52,7 @@ public bool OnPreUpdate(PreUpdateEvent @event) return false; } - private static ValidationContext CreateValidationContext(IDatabaseEventArgs @event, object entity) + static ValidationContext CreateValidationContext(IDatabaseEventArgs @event, object entity) { return new ValidationContext(entity, new SessionProvider(@event.Session), null); } diff --git a/Src/SharpArch.NHibernate/SharpArch.NHibernate.csproj b/Src/SharpArch.NHibernate/SharpArch.NHibernate.csproj index 9f3eb1bb6..337b83b11 100644 --- a/Src/SharpArch.NHibernate/SharpArch.NHibernate.csproj +++ b/Src/SharpArch.NHibernate/SharpArch.NHibernate.csproj @@ -17,9 +17,9 @@ - + - + diff --git a/Src/SharpArch.RavenDb/Contracts/Repositories/IRavenDbRepository.cs b/Src/SharpArch.RavenDb/Contracts/Repositories/IRavenDbRepository.cs index 56da621bb..b3c25ad75 100644 --- a/Src/SharpArch.RavenDb/Contracts/Repositories/IRavenDbRepository.cs +++ b/Src/SharpArch.RavenDb/Contracts/Repositories/IRavenDbRepository.cs @@ -22,18 +22,13 @@ public interface IRavenDbRepository : IRepository where TIdT : IEquatable { - /// - /// RavenDB Document Session. - /// - IAsyncDocumentSession Session { get; } - /// /// Finds all documents satisfying given criteria. /// /// The criteria. /// Cancellation token. /// Documents - Task> FindAllAsync(Expression> where, CancellationToken cancellationToken = default); + Task FindAllAsync(Expression> @where, CancellationToken cancellationToken = default); /// /// Finds single document satisfying given criteria. @@ -42,7 +37,7 @@ public interface IRavenDbRepository : IRepositoryCancellation token. /// The document /// If more than one document found. - Task FindOneAsync(Expression> where, CancellationToken cancellationToken = default); + Task FindOneAsync(Expression> @where, CancellationToken cancellationToken = default); /// /// Finds the first document satisfying given criteria. diff --git a/Src/SharpArch.RavenDb/RavenDbRepository.cs b/Src/SharpArch.RavenDb/RavenDbRepository.cs index 66737fd35..eeeda18ca 100644 --- a/Src/SharpArch.RavenDb/RavenDbRepository.cs +++ b/Src/SharpArch.RavenDb/RavenDbRepository.cs @@ -33,13 +33,13 @@ public class RavenDbRepository : IRavenDbRepository, /// /// RavenDB Document Session. /// - public IAsyncDocumentSession Session { get; } + protected IAsyncDocumentSession Session { get; } /// /// Initializes a new instance of the class. /// /// The session. - public RavenDbRepository([NotNull] IAsyncDocumentSession session) + public RavenDbRepository(IAsyncDocumentSession session) { Session = session ?? throw new ArgumentNullException(nameof(session)); TransactionManager = new TransactionManager(session); @@ -77,14 +77,14 @@ public IQueryable FindAll(ILinqSpecification specification) => specification.SatisfyingElementsFrom(FindAll()); /// - public async Task> FindAllAsync(Expression> where, CancellationToken cancellationToken = default) + public async Task FindAllAsync(Expression> @where, CancellationToken cancellationToken = default) { var result = await Session.Query().Where(where).ToArrayAsync(cancellationToken).ConfigureAwait(false); return result; } /// - public async Task FindOneAsync(Expression> where, CancellationToken cancellationToken = default) + public async Task FindOneAsync(Expression> @where, CancellationToken cancellationToken = default) { var result = await Session.Query().Where(where).SingleOrDefaultAsync(cancellationToken).ConfigureAwait(false); return result @@ -165,7 +165,5 @@ public async Task DeleteAsync(TId id, CancellationToken cancellationToken = defa } } - /// - IAsyncDocumentSession IRavenDbRepository.Session { get; } } } diff --git a/Src/SharpArch.RavenDb/SharpArch.RavenDb.csproj b/Src/SharpArch.RavenDb/SharpArch.RavenDb.csproj index 8a0e5ebd4..db4b67cab 100644 --- a/Src/SharpArch.RavenDb/SharpArch.RavenDb.csproj +++ b/Src/SharpArch.RavenDb/SharpArch.RavenDb.csproj @@ -16,9 +16,9 @@ - + - + diff --git a/Src/SharpArch.RavenDb/TransactionManager.cs b/Src/SharpArch.RavenDb/TransactionManager.cs index fcabb15c7..f79549086 100644 --- a/Src/SharpArch.RavenDb/TransactionManager.cs +++ b/Src/SharpArch.RavenDb/TransactionManager.cs @@ -21,15 +21,15 @@ namespace SharpArch.RavenDb [PublicAPI] public class TransactionManager : ITransactionManager, ISupportsTransactionStatus { - [NotNull] readonly IAsyncDocumentSession _session; + readonly IAsyncDocumentSession _session; - [CanBeNull] TransactionScope _transaction; + TransactionScope? _transaction; /// /// Initializes a new instance of the class. /// /// The document session. - public TransactionManager([NotNull] IAsyncDocumentSession session) + public TransactionManager(IAsyncDocumentSession session) { _session = session ?? throw new ArgumentNullException(nameof(session)); } @@ -74,27 +74,17 @@ public Task RollbackTransactionAsync(CancellationToken cancellationToken = defau [MethodImpl(MethodImplOptions.AggressiveInlining)] static System.Transactions.IsolationLevel MapIsolationLevel(IsolationLevel isolationLevel) - { - switch (isolationLevel) + => isolationLevel switch { - case IsolationLevel.Unspecified: - return System.Transactions.IsolationLevel.Unspecified; - case IsolationLevel.Chaos: - return System.Transactions.IsolationLevel.Chaos; - case IsolationLevel.ReadUncommitted: - return System.Transactions.IsolationLevel.ReadUncommitted; - case IsolationLevel.ReadCommitted: - return System.Transactions.IsolationLevel.ReadCommitted; - case IsolationLevel.RepeatableRead: - return System.Transactions.IsolationLevel.RepeatableRead; - case IsolationLevel.Serializable: - return System.Transactions.IsolationLevel.Serializable; - case IsolationLevel.Snapshot: - return System.Transactions.IsolationLevel.Snapshot; - default: - throw new ArgumentOutOfRangeException(nameof(isolationLevel), isolationLevel, null); - } - } + IsolationLevel.Unspecified => System.Transactions.IsolationLevel.Unspecified, + IsolationLevel.Chaos => System.Transactions.IsolationLevel.Chaos, + IsolationLevel.ReadUncommitted => System.Transactions.IsolationLevel.ReadUncommitted, + IsolationLevel.ReadCommitted => System.Transactions.IsolationLevel.ReadCommitted, + IsolationLevel.RepeatableRead => System.Transactions.IsolationLevel.RepeatableRead, + IsolationLevel.Serializable => System.Transactions.IsolationLevel.Serializable, + IsolationLevel.Snapshot => System.Transactions.IsolationLevel.Snapshot, + _ => throw new ArgumentOutOfRangeException(nameof(isolationLevel), isolationLevel, null) + }; void ClearTransaction() { diff --git a/Src/SharpArch.Testing.NUnit/NHibernate/DatabaseRepositoryTestsBase.cs b/Src/SharpArch.Testing.NUnit/NHibernate/DatabaseRepositoryTestsBase.cs index c3f14ff4a..18fcc1f28 100644 --- a/Src/SharpArch.Testing.NUnit/NHibernate/DatabaseRepositoryTestsBase.cs +++ b/Src/SharpArch.Testing.NUnit/NHibernate/DatabaseRepositoryTestsBase.cs @@ -43,12 +43,12 @@ public abstract class DatabaseRepositoryTestsBase /// /// Database initializer instance. /// - protected TestDatabaseSetup Initializer { get; private set; } + protected TestDatabaseSetup Initializer { get; private set; } = null!; /// /// Returns current NHibernate session. /// - protected ISession Session { get; private set; } + protected ISession? Session { get; private set; } DatabaseRepositoryTestsBase() { @@ -58,7 +58,7 @@ public abstract class DatabaseRepositoryTestsBase /// Constructor. /// /// - protected DatabaseRepositoryTestsBase([NotNull] TestDatabaseSetup initializer) + protected DatabaseRepositoryTestsBase(TestDatabaseSetup initializer) { Initializer = initializer ?? throw new ArgumentNullException(nameof(initializer)); } @@ -77,7 +77,7 @@ public void OneTimeSetUp() /// Can be used to override Session Factory settings. /// /// - protected virtual void UpdateConfiguration([NotNull] Configuration configuration) + protected virtual void UpdateConfiguration(Configuration configuration) { } @@ -115,7 +115,7 @@ public virtual void TearDown() public void OneTimeTearDown() { Initializer?.Dispose(); - Initializer = null; + Initializer = null!; } } } diff --git a/Src/SharpArch.Testing.NUnit/NHibernate/RepositoryTestsBase.cs b/Src/SharpArch.Testing.NUnit/NHibernate/RepositoryTestsBase.cs index a00ce6e9b..fe53d4906 100644 --- a/Src/SharpArch.Testing.NUnit/NHibernate/RepositoryTestsBase.cs +++ b/Src/SharpArch.Testing.NUnit/NHibernate/RepositoryTestsBase.cs @@ -21,19 +21,19 @@ public abstract class RepositoryTestsBase /// /// Transaction manager. /// - protected TransactionManager TransactionManager { get; private set; } + protected TransactionManager TransactionManager { get; private set; } = null!; /// /// Database initializer. /// - protected TestDatabaseSetup DbInitializer { get; private set; } + protected TestDatabaseSetup DbInitializer { get; private set; } = null!; /// /// Current NHibernate session. /// protected ISession Session => TransactionManager.Session; - private RepositoryTestsBase() + RepositoryTestsBase() { } @@ -41,7 +41,7 @@ private RepositoryTestsBase() /// Initializes database tests fixture. /// /// Database initializer instance. - protected RepositoryTestsBase([NotNull] TestDatabaseSetup dbInitializer) + protected RepositoryTestsBase(TestDatabaseSetup dbInitializer) { DbInitializer = dbInitializer ?? throw new ArgumentNullException(nameof(dbInitializer)); DbInitializer.GetSessionFactory(); @@ -54,7 +54,7 @@ protected RepositoryTestsBase([NotNull] TestDatabaseSetup dbInitializer) public void OneTimeTearDown() { DbInitializer?.Dispose(); - DbInitializer = null; + DbInitializer = null!; } /// @@ -71,7 +71,7 @@ public virtual void TearDown() /// /// The entity instance. /// is - protected void FlushSessionAndEvict([NotNull] object instance) + protected void FlushSessionAndEvict(object instance) { if (instance == null) throw new ArgumentNullException(nameof(instance)); Session.FlushAndEvict(instance); @@ -82,7 +82,7 @@ protected void FlushSessionAndEvict([NotNull] object instance) /// /// The entity instance. /// is - protected void SaveAndEvict([NotNull] object instance) + protected void SaveAndEvict(object instance) { if (instance == null) throw new ArgumentNullException(nameof(instance)); Session.Save(instance); diff --git a/Src/SharpArch.Testing.NUnit/SharpArch.Testing.NUnit.csproj b/Src/SharpArch.Testing.NUnit/SharpArch.Testing.NUnit.csproj index d77742781..14e802ac1 100644 --- a/Src/SharpArch.Testing.NUnit/SharpArch.Testing.NUnit.csproj +++ b/Src/SharpArch.Testing.NUnit/SharpArch.Testing.NUnit.csproj @@ -18,9 +18,9 @@ - + - + diff --git a/Src/SharpArch.Testing.Xunit.NHibernate/LiveDatabaseTests.cs b/Src/SharpArch.Testing.Xunit.NHibernate/LiveDatabaseTests.cs index 831d030d1..1ee23fca8 100644 --- a/Src/SharpArch.Testing.Xunit.NHibernate/LiveDatabaseTests.cs +++ b/Src/SharpArch.Testing.Xunit.NHibernate/LiveDatabaseTests.cs @@ -36,10 +36,13 @@ public abstract class LiveDatabaseTests : IClassFixture /// Returns current NHibernate session. /// - protected ISession Session { get; private set; } + protected ISession? Session { get; private set; } - /// - protected LiveDatabaseTests([NotNull] TDatabaseSetup setup) + /// + /// Creates instance of live database tests. + /// + /// Database setup, . + protected LiveDatabaseTests(TDatabaseSetup setup) { DbSetup = setup ?? throw new ArgumentNullException(nameof(setup)); Session = DbSetup.GetSessionFactory().OpenSession(); diff --git a/Src/SharpArch.Testing.Xunit.NHibernate/SharpArch.Testing.Xunit.NHibernate.csproj b/Src/SharpArch.Testing.Xunit.NHibernate/SharpArch.Testing.Xunit.NHibernate.csproj index c86f850d6..30649e2ca 100644 --- a/Src/SharpArch.Testing.Xunit.NHibernate/SharpArch.Testing.Xunit.NHibernate.csproj +++ b/Src/SharpArch.Testing.Xunit.NHibernate/SharpArch.Testing.Xunit.NHibernate.csproj @@ -18,7 +18,7 @@ - + diff --git a/Src/SharpArch.Testing.Xunit/SetCultureAttribute.cs b/Src/SharpArch.Testing.Xunit/SetCultureAttribute.cs index 6b07b33de..c90b46474 100644 --- a/Src/SharpArch.Testing.Xunit/SetCultureAttribute.cs +++ b/Src/SharpArch.Testing.Xunit/SetCultureAttribute.cs @@ -19,8 +19,8 @@ public sealed class SetCultureAttribute : BeforeAfterTestAttribute { readonly Lazy _culture; readonly Lazy _uiCulture; - CultureInfo _originalCulture; - CultureInfo _originalUiCulture; + CultureInfo? _originalCulture; + CultureInfo? _originalUiCulture; /// /// Overrides the culture and UI culture of the current thread given culture. @@ -37,7 +37,7 @@ public SetCultureAttribute(string culture) /// /// The name of the culture. /// The name of the UI culture. - public SetCultureAttribute([NotNull] string culture, [NotNull] string uiCulture) + public SetCultureAttribute(string culture, string uiCulture) { if (string.IsNullOrWhiteSpace(culture)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(culture)); if (string.IsNullOrWhiteSpace(uiCulture)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(uiCulture)); @@ -71,8 +71,10 @@ static void ClearCachedData() /// public override void After(MethodInfo methodUnderTest) { - CultureInfo.CurrentCulture = _originalCulture; - CultureInfo.CurrentUICulture = _originalUiCulture; + if (_originalCulture != null) + CultureInfo.CurrentCulture = _originalCulture; + if (_originalUiCulture != null) + CultureInfo.CurrentUICulture = _originalUiCulture; ClearCachedData(); } } diff --git a/Src/SharpArch.Testing.Xunit/SharpArch.Testing.Xunit.csproj b/Src/SharpArch.Testing.Xunit/SharpArch.Testing.Xunit.csproj index f947da98d..8b21a8167 100644 --- a/Src/SharpArch.Testing.Xunit/SharpArch.Testing.Xunit.csproj +++ b/Src/SharpArch.Testing.Xunit/SharpArch.Testing.Xunit.csproj @@ -16,7 +16,7 @@ - + diff --git a/Src/SharpArch.Testing/Helpers/EntityIdSetter.cs b/Src/SharpArch.Testing/Helpers/EntityIdSetter.cs index 7ac734a8c..218395a72 100644 --- a/Src/SharpArch.Testing/Helpers/EntityIdSetter.cs +++ b/Src/SharpArch.Testing/Helpers/EntityIdSetter.cs @@ -20,12 +20,12 @@ public static class EntityIdSetter /// /// is . /// Property with name 'Id' could not be found. - public static void SetIdOf([NotNull] IEntity entity, TId id) + public static void SetIdOf(IEntity entity, TId id) where TId : IEquatable { if (entity == null) throw new ArgumentNullException(nameof(entity)); // Set the data property reflectively - PropertyInfo idProperty = entity.GetType().GetProperty("Id", BindingFlags.Public | BindingFlags.Instance); + PropertyInfo? idProperty = entity.GetType().GetProperty("Id", BindingFlags.Public | BindingFlags.Instance); if (idProperty == null) throw new InvalidOperationException("Property with name 'Id' could not be found."); diff --git a/Src/SharpArch.Testing/SharpArch.Testing.csproj b/Src/SharpArch.Testing/SharpArch.Testing.csproj index bc11f0468..1cd64c9c8 100644 --- a/Src/SharpArch.Testing/SharpArch.Testing.csproj +++ b/Src/SharpArch.Testing/SharpArch.Testing.csproj @@ -16,7 +16,7 @@ - + diff --git a/Src/SharpArch.Web.AspNetCore/SharpArch.Web.AspNetCore.csproj b/Src/SharpArch.Web.AspNetCore/SharpArch.Web.AspNetCore.csproj index 5ae57636d..e4a357404 100644 --- a/Src/SharpArch.Web.AspNetCore/SharpArch.Web.AspNetCore.csproj +++ b/Src/SharpArch.Web.AspNetCore/SharpArch.Web.AspNetCore.csproj @@ -21,21 +21,21 @@ - + - - - + + + - + diff --git a/Src/SharpArch.Web.AspNetCore/Transaction/ApplyTransactionFilterBase.cs b/Src/SharpArch.Web.AspNetCore/Transaction/ApplyTransactionFilterBase.cs index 54ee14cf5..d214aca83 100644 --- a/Src/SharpArch.Web.AspNetCore/Transaction/ApplyTransactionFilterBase.cs +++ b/Src/SharpArch.Web.AspNetCore/Transaction/ApplyTransactionFilterBase.cs @@ -12,22 +12,22 @@ [PublicAPI] public abstract class ApplyTransactionFilterBase { - static readonly object _lock = new object(); + static readonly object _lock = new(); - static ImmutableDictionary _attributeCache - = ImmutableDictionary.Empty; + static ImmutableDictionary _attributeCache + = ImmutableDictionary.Empty; /// /// Returns associated with given action. /// /// /// instance or null. - protected TransactionAttribute GetTransactionAttribute(FilterContext context) + protected TransactionAttribute? GetTransactionAttribute(FilterContext context) { var actionId = context.ActionDescriptor.Id; if (!_attributeCache.TryGetValue(actionId, out var transactionAttribute)) { - lock(_lock) + lock (_lock) { transactionAttribute = context.FindEffectivePolicy(); if (!_attributeCache.ContainsKey(actionId)) diff --git a/Src/SharpArch.Web.AspNetCore/Transaction/AutoTransactionHandler.cs b/Src/SharpArch.Web.AspNetCore/Transaction/AutoTransactionHandler.cs index 7dd1d0c5e..4c2bf0e2a 100644 --- a/Src/SharpArch.Web.AspNetCore/Transaction/AutoTransactionHandler.cs +++ b/Src/SharpArch.Web.AspNetCore/Transaction/AutoTransactionHandler.cs @@ -22,7 +22,7 @@ public class AutoTransactionHandler : ApplyTransactionFilterBase, IAsyncActionFi public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { var transactionAttribute = GetTransactionAttribute(context); - ITransactionManager transactionManager = null; + ITransactionManager? transactionManager = null; if (transactionAttribute != null) { transactionManager = context.HttpContext.RequestServices.GetRequiredService(); @@ -41,7 +41,7 @@ public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionE } if (executedContext.Exception != null || - transactionAttribute.RollbackOnModelValidationError && context.ModelState.IsValid == false) + transactionAttribute!.RollbackOnModelValidationError && context.ModelState.IsValid == false) { // don't use cancellation token to ensure transaction is rolled back on error await transactionManager.RollbackTransactionAsync().ConfigureAwait(false); diff --git a/Src/SharpArch.Web.AspNetCore/Transaction/TransactionAttribute.cs b/Src/SharpArch.Web.AspNetCore/Transaction/TransactionAttribute.cs index 367cc14ad..a70329576 100644 --- a/Src/SharpArch.Web.AspNetCore/Transaction/TransactionAttribute.cs +++ b/Src/SharpArch.Web.AspNetCore/Transaction/TransactionAttribute.cs @@ -30,7 +30,7 @@ namespace SharpArch.Web.AspNetCore.Transaction [BaseTypeRequired(typeof(ControllerBase))] [PublicAPI] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] - public sealed class TransactionAttribute : Attribute, IFilterMetadata + public sealed class TransactionAttribute : Attribute, IFilterMetadata, IEquatable { /// /// Gets or sets a value indicating whether rollback transaction in case of model validation error. @@ -60,5 +60,43 @@ public TransactionAttribute(IsolationLevel isolationLevel = IsolationLevel.ReadC IsolationLevel = isolationLevel; RollbackOnModelValidationError = rollbackOnModelValidationError; } + + /// + public bool Equals(TransactionAttribute? other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return RollbackOnModelValidationError == other.RollbackOnModelValidationError && IsolationLevel == other.IsolationLevel; + } + + /// + public override bool Equals(object? obj) + => ReferenceEquals(this, obj) || obj is TransactionAttribute other && Equals(other); + + /// + public override int GetHashCode() + { + int hashCode = RollbackOnModelValidationError ? 397 : 0; + hashCode ^= (int) IsolationLevel; + return hashCode; + } + + /// + /// Checks whether have same settings. + /// + /// Left operand. + /// Right operand. + /// true if transaction attribute parameters are the same; otherwise false. + public static bool operator ==(TransactionAttribute? left, TransactionAttribute? right) + => Equals(left, right); + + /// + /// Checks whether have different settings. + /// + /// Left operand. + /// Right operand. + /// true if transaction attribute parameters are the different; otherwise false. + public static bool operator !=(TransactionAttribute? left, TransactionAttribute? right) + => !Equals(left, right); } } diff --git a/Src/Tests/SharpArch.Tests.NHibernate/HasUniqieDomainSignatureTestsBase.cs b/Src/Tests/SharpArch.Tests.NHibernate/HasUniqieDomainSignatureTestsBase.cs index bb1a36cab..ce0071174 100644 --- a/Src/Tests/SharpArch.Tests.NHibernate/HasUniqieDomainSignatureTestsBase.cs +++ b/Src/Tests/SharpArch.Tests.NHibernate/HasUniqieDomainSignatureTestsBase.cs @@ -13,7 +13,7 @@ internal class HasUniqueDomainSignatureTestsBase : RepositoryTestsBase { - protected Mock ServiceProviderMock; + protected Mock ServiceProviderMock = null!; public HasUniqueDomainSignatureTestsBase() : base(new TestDatabaseSetup( diff --git a/Src/Tests/SharpArch.Tests.NHibernate/NHibernateSessionFactoryBuilderTests.cs b/Src/Tests/SharpArch.Tests.NHibernate/NHibernateSessionFactoryBuilderTests.cs index 65e67453b..07615b112 100644 --- a/Src/Tests/SharpArch.Tests.NHibernate/NHibernateSessionFactoryBuilderTests.cs +++ b/Src/Tests/SharpArch.Tests.NHibernate/NHibernateSessionFactoryBuilderTests.cs @@ -32,7 +32,7 @@ public void TearDown() } } - string _tempFileName; + string _tempFileName = null!; static string GetConfigFullName() { diff --git a/Src/Tests/SharpArch.Tests.NHibernate/RepositoryTests.cs b/Src/Tests/SharpArch.Tests.NHibernate/RepositoryTests.cs index 29b8a446c..4008fec67 100644 --- a/Src/Tests/SharpArch.Tests.NHibernate/RepositoryTests.cs +++ b/Src/Tests/SharpArch.Tests.NHibernate/RepositoryTests.cs @@ -33,6 +33,6 @@ public void CanCastConcreteLinqRepositoryToInterfaceILinqRepository() public class MyEntity: Entity { - string Name { get; set; } + string? Name { get; set; } } } diff --git a/Src/Tests/SharpArch.Tests.NHibernate/SharpArch.Tests.NHibernate.csproj b/Src/Tests/SharpArch.Tests.NHibernate/SharpArch.Tests.NHibernate.csproj index f604b86d4..2fbb79c67 100644 --- a/Src/Tests/SharpArch.Tests.NHibernate/SharpArch.Tests.NHibernate.csproj +++ b/Src/Tests/SharpArch.Tests.NHibernate/SharpArch.Tests.NHibernate.csproj @@ -11,10 +11,10 @@ - - - - + + + + diff --git a/Src/Tests/SharpArch.XunitTests.NHibernate/HasUniqieDomainSignatureTestsBase.cs b/Src/Tests/SharpArch.XunitTests.NHibernate/HasUniqieDomainSignatureTestsBase.cs index f602521a8..b080f05c1 100644 --- a/Src/Tests/SharpArch.XunitTests.NHibernate/HasUniqieDomainSignatureTestsBase.cs +++ b/Src/Tests/SharpArch.XunitTests.NHibernate/HasUniqieDomainSignatureTestsBase.cs @@ -10,8 +10,8 @@ public abstract class HasUniqueDomainSignatureTestsBase : TransientDatabaseTests { - protected Mock ServiceProviderMock; - protected ValidationContext ValidationContext; + protected readonly Mock ServiceProviderMock; + protected ValidationContext? ValidationContext; public HasUniqueDomainSignatureTestsBase() : base(new NHibernateTestsSetup()) @@ -28,7 +28,7 @@ public HasUniqueDomainSignatureTestsBase() /// protected ValidationContext ValidationContextFor(object objectToValidate) { - return new ValidationContext(objectToValidate, ServiceProviderMock.Object, null); + return new(objectToValidate, ServiceProviderMock.Object, null); } } } diff --git a/Src/Tests/SharpArch.XunitTests.NHibernate/RepositoryTests.cs b/Src/Tests/SharpArch.XunitTests.NHibernate/RepositoryTests.cs index 721606be6..140419d03 100644 --- a/Src/Tests/SharpArch.XunitTests.NHibernate/RepositoryTests.cs +++ b/Src/Tests/SharpArch.XunitTests.NHibernate/RepositoryTests.cs @@ -27,6 +27,6 @@ public void CanCastConcreteLinqRepositoryToInterfaceILinqRepository() public class MyEntity: Entity { - string Name { get; set; } + string? Name { get; set; } } } diff --git a/Src/Tests/SharpArch.XunitTests.NHibernate/SharpArch.XunitTests.NHibernate.csproj b/Src/Tests/SharpArch.XunitTests.NHibernate/SharpArch.XunitTests.NHibernate.csproj index ac25e2b89..1f0482511 100644 --- a/Src/Tests/SharpArch.XunitTests.NHibernate/SharpArch.XunitTests.NHibernate.csproj +++ b/Src/Tests/SharpArch.XunitTests.NHibernate/SharpArch.XunitTests.NHibernate.csproj @@ -8,10 +8,10 @@ - - - - + + + + diff --git a/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/DataAnnotationsValidator/HasUniqueEntitySignatureValidatorTests.cs b/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/DataAnnotationsValidator/HasUniqueEntitySignatureValidatorTests.cs index d03310eab..4dce02582 100644 --- a/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/DataAnnotationsValidator/HasUniqueEntitySignatureValidatorTests.cs +++ b/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/DataAnnotationsValidator/HasUniqueEntitySignatureValidatorTests.cs @@ -33,7 +33,7 @@ ValidationContext ValidationContextFor(object instance) class Contractor : Entity { [DomainSignature] - public string Name { get; set; } + public string Name { get; set; } = null!; } @@ -62,7 +62,7 @@ public bool DoesDuplicateExistWithTypedIdOf(IEntity entity) class ObjectWithGuidId : Entity { [DomainSignature] - public string Name { get; set; } + public string? Name { get; set; } } @@ -70,7 +70,7 @@ class ObjectWithGuidId : Entity class ObjectWithStringIdAndValidatorForIntId : Entity { [DomainSignature] - public string Name { get; set; } + public string? Name { get; set; } } @@ -78,7 +78,7 @@ class ObjectWithStringIdAndValidatorForIntId : Entity class User : Entity { [DomainSignature] - public string Ssn { get; set; } + public string? Ssn { get; set; } } diff --git a/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/DomainModel/BaseObjectEqualityComparerTests.cs b/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/DomainModel/BaseObjectEqualityComparerTests.cs index 838bef75c..cea716051 100644 --- a/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/DomainModel/BaseObjectEqualityComparerTests.cs +++ b/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/DomainModel/BaseObjectEqualityComparerTests.cs @@ -13,7 +13,7 @@ public class BaseObjectEqualityComparerTests { class ConcreteBaseObject : BaseObject { - public string Name { get; set; } + public string Name { get; set; } = null!; protected override PropertyInfo[] GetTypeSpecificSignatureProperties() { @@ -25,19 +25,19 @@ protected override PropertyInfo[] GetTypeSpecificSignatureProperties() class ConcreteEntityWithDomainSignatureProperties : Entity { [DomainSignature] - public string Name { get; set; } + public string Name { get; set; } = null!; } class ConcreteEntityWithNoDomainSignatureProperties : Entity { - public string Name { get; set; } + public string Name { get; set; } = null!; } class ConcreteValueObject : ValueObject { - public string Name { get; set; } + public string Name { get; set; } = null!; } diff --git a/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/DomainModel/EntityTests.cs b/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/DomainModel/EntityTests.cs index 420da7933..03b00fd64 100644 --- a/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/DomainModel/EntityTests.cs +++ b/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/DomainModel/EntityTests.cs @@ -67,13 +67,13 @@ public EntityTests() public abstract class MockEntityObjectBase : Entity where T : IEquatable { - public string Email { get; set; } + public string? Email { get; set; } [DomainSignature] - public string FirstName { get; set; } + public string FirstName { get; set; } = null!; [DomainSignature] - public string LastName { get; set; } + public string LastName { get; set; } = null!; } @@ -82,16 +82,16 @@ public class ObjectWithOneDomainSignatureProperty : Entity [DomainSignature] public int Age { get; set; } - public string Name { get; set; } + public string? Name { get; set; } } class AddressBeingDomainSignatureComparable : Entity { [DomainSignature] - public string Address1 { get; set; } + public string Address1 { get; set; } = null!; - public string Address2 { get; set; } + public string? Address2 { get; set; } [DomainSignature] public int ZipCode { get; set; } @@ -100,7 +100,7 @@ class AddressBeingDomainSignatureComparable : Entity class InheritedObjectWithExtraDomainSignatureProperty : ObjectWithOneDomainSignatureProperty { - public string Address { get; set; } + public string? Address { get; set; } [DomainSignature] public bool IsLiving { get; set; } @@ -146,14 +146,14 @@ class ObjectWithAllDomainSignatureProperty : Entity public int Age { get; set; } [DomainSignature] - public string Name { get; set; } + public string? Name { get; set; } } class ObjectWithAssignedId : Entity, IHasAssignedId { [DomainSignature] - public string Name { get; set; } + public string? Name { get; set; } public void SetAssignedIdTo(string assignedId) { @@ -165,30 +165,30 @@ public void SetAssignedIdTo(string assignedId) class ObjectWithComplexProperties : Entity { [DomainSignature] - public AddressBeingDomainSignatureComparable Address { get; set; } + public AddressBeingDomainSignatureComparable? Address { get; set; } [DomainSignature] - public string Name { get; set; } + public string? Name { get; set; } [DomainSignature] - public PhoneBeingNotDomainObject Phone { get; set; } + public PhoneBeingNotDomainObject? Phone { get; set; } } class ObjectWithIdenticalTypedProperties : Entity { [DomainSignature] - public string Address { get; set; } + public string? Address { get; set; } [DomainSignature] - public string Name { get; set; } + public string? Name { get; set; } } class ObjectWithIntId : Entity { [DomainSignature] - public string Name { get; set; } + public string? Name { get; set; } } @@ -200,21 +200,21 @@ class ObjectWithNoDomainSignatureProperties : Entity { public int Age { get; set; } - public string Name { get; set; } + public string? Name { get; set; } } class PhoneBeingNotDomainObject { - public string Extension { get; set; } + public string? Extension { get; set; } - public string PhoneNumber { get; set; } + public string PhoneNumber { get; set; } = null!; } class PhoneBeingNotDomainObjectButWithOverriddenEquals : PhoneBeingNotDomainObject { - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is PhoneBeingNotDomainObject compareTo && PhoneNumber.Equals(compareTo.PhoneNumber); } @@ -229,7 +229,7 @@ public override int GetHashCode() class Contact : Entity { - public virtual string EmailAddress { get; set; } + public virtual string? EmailAddress { get; set; } } @@ -283,7 +283,7 @@ public void CanCompareEntities() var obj2 = new ObjectWithIntId {Name = "Anvil"}; obj1.Equals(null).Should().BeFalse(); - obj1.Equals(obj2).Should().BeFalse(); + obj1!.Equals(obj2).Should().BeFalse(); EntityIdSetter.SetIdOf(obj1, 10); EntityIdSetter.SetIdOf(obj2, 10); @@ -312,7 +312,7 @@ public void CanCompareEntitiesWithAssignedIds() var obj2 = new ObjectWithAssignedId {Name = "Anvil"}; obj1.Equals(null).Should().BeFalse(); - obj1.Equals(obj2).Should().BeFalse(); + obj1!.Equals(obj2).Should().BeFalse(); obj1.SetAssignedIdTo("AAAAA"); obj2.SetAssignedIdTo("AAAAA"); diff --git a/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/DomainModel/ValueObjectTests.cs b/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/DomainModel/ValueObjectTests.cs index 77fb64de3..f87bc3c0f 100644 --- a/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/DomainModel/ValueObjectTests.cs +++ b/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/DomainModel/ValueObjectTests.cs @@ -13,7 +13,7 @@ public class AnotherDummyValueType : ValueObject { public int Id { get; set; } - public string Name { get; set; } + public string? Name { get; set; } } @@ -21,7 +21,7 @@ public class DummyValueType : ValueObject { public int Id { get; set; } - public string Name { get; set; } + public string? Name { get; set; } } @@ -32,7 +32,7 @@ public class DummyValueType : ValueObject public class ValueObjectWithDomainSignature : ValueObject { [DomainSignature] - public string Name { get; set; } + public string? Name { get; set; } } @@ -114,7 +114,7 @@ public void ShouldNotBeEqualToNullWithOperators() (null == val1).Should().BeFalse(); (val1 == null).Should().BeFalse(); - (null != val1).Should().BeTrue(); + (null! != val1).Should().BeTrue(); (val1 != null).Should().BeTrue(); } diff --git a/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/TestEntities.cs b/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/TestEntities.cs index d9d6b4e56..13bba2410 100644 --- a/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/TestEntities.cs +++ b/Src/Tests/SharpArch.XunitTests/SharpArch.Domain/TestEntities.cs @@ -11,7 +11,7 @@ namespace Tests.SharpArch.Domain public class Contractor : Entity { [DomainSignature] - public virtual string Name { get; set; } + public virtual string Name { get; set; } = null!; } @@ -19,7 +19,7 @@ public class Contractor : Entity public class ObjectWithGuidId : Entity { [DomainSignature] - public virtual string Name { get; set; } + public virtual string Name { get; set; } = null!; } @@ -27,7 +27,7 @@ public class ObjectWithGuidId : Entity internal class ObjectWithStringIdAndValidatorForIntId : Entity { [DomainSignature] - public virtual string Name { get; set; } + public virtual string Name { get; set; } = null!; } @@ -35,7 +35,7 @@ internal class ObjectWithStringIdAndValidatorForIntId : Entity public class User : Entity { [DomainSignature] - public virtual string Ssn { get; set; } + public virtual string Ssn { get; set; } = null!; public User(string id, string ssn) { @@ -51,7 +51,7 @@ public User() internal class EntityWithNoDomainSignatureProperties : Entity { - public virtual string Property1 { get; set; } + public virtual string Property1 { get; set; } = null!; public virtual int Property2 { get; set; } } @@ -60,7 +60,7 @@ internal class EntityWithNoDomainSignatureProperties : Entity internal class EntityWithAllPropertiesPartOfDomainSignature : Entity { [DomainSignature] - public virtual string Property1 { get; set; } + public virtual string Property1 { get; set; } = null!; [DomainSignature] public virtual int Property2 { get; set; } @@ -73,7 +73,7 @@ internal class EntityWithAllPropertiesPartOfDomainSignature : Entity internal class EntityWithSomePropertiesPartOfDomainSignature : Entity { [DomainSignature] - public virtual string Property1 { get; set; } + public virtual string Property1 { get; set; } = null!; public virtual int Property2 { get; set; } @@ -85,7 +85,7 @@ internal class EntityWithSomePropertiesPartOfDomainSignature : Entity internal class EntityWithAnotherEntityAsPartOfDomainSignature : Entity { [DomainSignature] - public virtual string Property1 { get; set; } + public virtual string Property1 { get; set; } = null!; [DomainSignature] public virtual EntityWithAllPropertiesPartOfDomainSignature Property2 { get; set; } @@ -101,10 +101,10 @@ public EntityWithAnotherEntityAsPartOfDomainSignature() public class Song : Entity { [DomainSignature] - public virtual string SongTitle { get; set; } + public virtual string? SongTitle { get; set; } [DomainSignature] - public virtual Band Performer { get; set; } + public virtual Band? Performer { get; set; } } @@ -113,7 +113,7 @@ public class Band : Entity { [DomainSignature] [Required] - public virtual string BandName { get; set; } + public virtual string BandName { get; set; } = null!; public virtual DateTime DateFormed { get; set; } } @@ -124,17 +124,17 @@ public class Album : Entity { [DomainSignature] [Required] - public virtual string Title { get; set; } + public virtual string Title { get; set; } = null!; - public virtual Band Author { get; set; } + public virtual Band? Author { get; set; } } public class Address : ValueObject { - public virtual string StreetAddress { get; set; } + public virtual string? StreetAddress { get; set; } - public virtual string PostCode { get; set; } + public virtual string? PostCode { get; set; } } @@ -142,9 +142,9 @@ public class Address : ValueObject public class Customer : Entity { [DomainSignature] - public virtual string Name { get; set; } + public virtual string? Name { get; set; } [DomainSignature] - public virtual Address Address { get; set; } + public virtual Address? Address { get; set; } } } diff --git a/Src/Tests/SharpArch.XunitTests/SharpArch.XunitTests.csproj b/Src/Tests/SharpArch.XunitTests/SharpArch.XunitTests.csproj index e8060a606..bf9311925 100644 --- a/Src/Tests/SharpArch.XunitTests/SharpArch.XunitTests.csproj +++ b/Src/Tests/SharpArch.XunitTests/SharpArch.XunitTests.csproj @@ -8,9 +8,9 @@ - - - + + + all diff --git a/VersionHistory.txt b/VersionHistory.txt index 62a5315d2..d69fee63d 100644 --- a/VersionHistory.txt +++ b/VersionHistory.txt @@ -6,7 +6,11 @@ BREAKING: * Removed EntityWithTypedId<> replaced with Entity<>, removed old entity class. Fix: replace `Entity` with `Entity`. * Renamed IAsyncRepository to IRepository. * Added IEquatable constraint on IEntity. +* IRavenDbRepository.FindAllAsync now returns Task, not Task>. +* Removed IRavenDbRepository.Session. +IMPROVEMENTS: +* TransactionAttribute now implements Equitable<> S#arp 6.1.1 ======================== From b18d8d267a3e03127a6aeee8ea5ac0c97f3bd587 Mon Sep 17 00:00:00 2001 From: vk Date: Sun, 11 Apr 2021 21:45:48 -0400 Subject: [PATCH 11/13] Remove redundant annotations, fixes #239 --- Samples/TransactionAttribute/App/Program.cs | 4 +-- Src/Common/NHibernate/TestDatabaseSetup.cs | 12 ++++----- .../IEntityDuplicateChecker.cs | 2 +- .../PersistenceSupport/ILinqRepository.cs | 8 +++--- .../PersistenceSupport/IRepository.cs | 18 ++++++------- .../RepositoryExtensions.cs | 2 +- .../Logging/EnabledLogLevel.cs | 8 +++--- .../Logging/EnabledLogger.cs | 4 +-- .../NHibernateRegistrationExtensions.cs | 2 +- .../IAutoPersistenceModelGenerator.cs | 2 +- .../FluentNHibernate/IMapGenerator.cs | 2 +- .../ISessionFactoryKeyProvider.cs | 6 ++--- Src/SharpArch.NHibernate/NHibernateQuery.cs | 4 +-- .../NHibernateRepositoryBase.cs | 8 +++--- .../NHibernateSessionFactoryBuilder.cs | 26 +++++++++---------- Src/SharpArch.NHibernate/SessionExtensions.cs | 10 +++---- .../TransactionManager.cs | 2 +- .../TransientDatabaseTests.cs | 16 ++++++------ 18 files changed, 68 insertions(+), 68 deletions(-) diff --git a/Samples/TransactionAttribute/App/Program.cs b/Samples/TransactionAttribute/App/Program.cs index a6be726f6..382ed75f9 100644 --- a/Samples/TransactionAttribute/App/Program.cs +++ b/Samples/TransactionAttribute/App/Program.cs @@ -22,7 +22,7 @@ [UsedImplicitly] public class Program { - public static int Main([NotNull] string[] args) + public static int Main(string[] args) { try { @@ -42,7 +42,7 @@ public static int Main([NotNull] string[] args) } } - [NotNull] + public static IWebHostBuilder CreateHostBuilder() { return new WebHostBuilder() diff --git a/Src/Common/NHibernate/TestDatabaseSetup.cs b/Src/Common/NHibernate/TestDatabaseSetup.cs index 58ff1f875..64f1af843 100644 --- a/Src/Common/NHibernate/TestDatabaseSetup.cs +++ b/Src/Common/NHibernate/TestDatabaseSetup.cs @@ -93,8 +93,8 @@ public virtual void Dispose() /// allowed. /// /// Unable to instantiate AutoPersistenceModelGenerator. - [NotNull] - public static AutoPersistenceModel GenerateAutoPersistenceModel([NotNull] Assembly[] assemblies) + + public static AutoPersistenceModel GenerateAutoPersistenceModel(Assembly[] assemblies) { if (assemblies == null) throw new ArgumentNullException(nameof(assemblies)); var persistenceGeneratorTypes = assemblies.SelectMany(a => @@ -128,7 +128,7 @@ public static AutoPersistenceModel GenerateAutoPersistenceModel([NotNull] Assemb /// Returns NHibernate . /// Configuration instance is cached, all subsequent calls will return the same instance. /// - [NotNull] + public Configuration GetConfiguration() { if (_configuration != null) return _configuration; @@ -159,7 +159,7 @@ public Configuration GetConfiguration() /// /// /// - protected virtual void Customize([NotNull] NHibernateSessionFactoryBuilder builder) + protected virtual void Customize(NHibernateSessionFactoryBuilder builder) { } @@ -167,7 +167,7 @@ protected virtual void Customize([NotNull] NHibernateSessionFactoryBuilder build /// Returns NHibernate . /// Session factory instance is cached, all subsequent calls to GetSessionFactory() will return the same instance. /// - [NotNull] + public ISessionFactory GetSessionFactory() { if (_sessionFactory != null) return _sessionFactory; @@ -179,7 +179,7 @@ public ISessionFactory GetSessionFactory() /// Creates new NHibernate session and initializes database structure. /// /// NHibernate Session - [NotNull] + public ISession InitializeSession() { var session = GetSessionFactory().OpenSession(); diff --git a/Src/SharpArch.Domain/PersistenceSupport/IEntityDuplicateChecker.cs b/Src/SharpArch.Domain/PersistenceSupport/IEntityDuplicateChecker.cs index 00a068737..e2ee4c583 100644 --- a/Src/SharpArch.Domain/PersistenceSupport/IEntityDuplicateChecker.cs +++ b/Src/SharpArch.Domain/PersistenceSupport/IEntityDuplicateChecker.cs @@ -16,6 +16,6 @@ public interface IEntityDuplicateChecker /// /// true if a duplicate exists, false otherwise. /// - bool DoesDuplicateExistWithTypedIdOf([NotNull] IEntity entity); + bool DoesDuplicateExistWithTypedIdOf(IEntity entity); } } diff --git a/Src/SharpArch.Domain/PersistenceSupport/ILinqRepository.cs b/Src/SharpArch.Domain/PersistenceSupport/ILinqRepository.cs index be624efc1..d19ada8c3 100644 --- a/Src/SharpArch.Domain/PersistenceSupport/ILinqRepository.cs +++ b/Src/SharpArch.Domain/PersistenceSupport/ILinqRepository.cs @@ -37,13 +37,13 @@ public interface ILinqRepository : IRepository /// Cancellation token. /// The matching item. [ItemCanBeNull] - Task FindOneAsync([NotNull] ILinqSpecification specification, CancellationToken cancellationToken = default); + Task FindOneAsync(ILinqSpecification specification, CancellationToken cancellationToken = default); /// /// Returns representing query for the entity. /// /// Query. - [NotNull] + IQueryable FindAll(); /// @@ -51,7 +51,7 @@ public interface ILinqRepository : IRepository /// /// The specification. /// Query. - [NotNull] - IQueryable FindAll([NotNull] ILinqSpecification specification); + + IQueryable FindAll(ILinqSpecification specification); } } diff --git a/Src/SharpArch.Domain/PersistenceSupport/IRepository.cs b/Src/SharpArch.Domain/PersistenceSupport/IRepository.cs index 845efc9c4..ebb659df2 100644 --- a/Src/SharpArch.Domain/PersistenceSupport/IRepository.cs +++ b/Src/SharpArch.Domain/PersistenceSupport/IRepository.cs @@ -24,7 +24,7 @@ public interface IRepository /// activities such as committing any pending changes, beginning a transaction, /// rolling back a transaction, etc. /// - [NotNull] + ITransactionManager TransactionManager { get; } /// @@ -33,14 +33,14 @@ public interface IRepository /// /// An entity or null if a row is not found matching the provided ID. /// - [NotNull] + [ItemCanBeNull] Task GetAsync(TId id, CancellationToken cancellationToken = default); /// /// Returns all of the items of a given type. /// - [NotNull] + [ItemNotNull] Task> GetAllAsync(CancellationToken cancellationToken = default); @@ -52,9 +52,9 @@ public interface IRepository /// Saved entity instance. /// /// is null. - [NotNull] + [ItemNotNull] - Task SaveAsync([NotNull] TEntity entity, CancellationToken cancellationToken = default); + Task SaveAsync(TEntity entity, CancellationToken cancellationToken = default); /// /// Saves or updates the specified entity. @@ -74,9 +74,9 @@ public interface IRepository /// Entity instance. /// /// is null. - [NotNull] + [ItemNotNull] - Task SaveOrUpdateAsync([NotNull] TEntity entity, CancellationToken cancellationToken = default); + Task SaveOrUpdateAsync(TEntity entity, CancellationToken cancellationToken = default); /// /// Disassociates the entity with the ORM so that changes made to it are not automatically @@ -87,13 +87,13 @@ public interface IRepository /// More details may be found at http://www.hibernate.org/hib_docs/nhibernate/html_single/#performance-sessioncache. /// /// is null. - Task EvictAsync([NotNull] TEntity entity, CancellationToken cancellationToken = default); + Task EvictAsync(TEntity entity, CancellationToken cancellationToken = default); /// /// Deletes the specified entity. /// /// is null. - Task DeleteAsync([NotNull] TEntity entity, CancellationToken cancellationToken = default); + Task DeleteAsync(TEntity entity, CancellationToken cancellationToken = default); /// /// Deletes the entity that matches the provided Id. diff --git a/Src/SharpArch.Domain/PersistenceSupport/RepositoryExtensions.cs b/Src/SharpArch.Domain/PersistenceSupport/RepositoryExtensions.cs index c786df8e7..8914cadad 100644 --- a/Src/SharpArch.Domain/PersistenceSupport/RepositoryExtensions.cs +++ b/Src/SharpArch.Domain/PersistenceSupport/RepositoryExtensions.cs @@ -21,7 +21,7 @@ public static class RepositoryExtensions /// . /// public static async Task SaveAndEvictAsync( - [NotNull] this IRepository repository, [NotNull] TEntity entity, CancellationToken cancellationToken = default) + this IRepository repository, TEntity entity, CancellationToken cancellationToken = default) where TEntity : class, IEntity where TId : IEquatable { diff --git a/Src/SharpArch.Infrastructure/Logging/EnabledLogLevel.cs b/Src/SharpArch.Infrastructure/Logging/EnabledLogLevel.cs index ceceb1e03..4453087a4 100644 --- a/Src/SharpArch.Infrastructure/Logging/EnabledLogLevel.cs +++ b/Src/SharpArch.Infrastructure/Logging/EnabledLogLevel.cs @@ -10,7 +10,7 @@ namespace SharpArch.Infrastructure.Logging /// public readonly struct EnabledLogLevel { - [NotNull] readonly ILogger _logger; + readonly ILogger _logger; readonly LogLevel _level; /// @@ -18,7 +18,7 @@ public readonly struct EnabledLogLevel /// /// Logger. /// Log level to use. - internal EnabledLogLevel([NotNull] ILogger logger, LogLevel level) + internal EnabledLogLevel(ILogger logger, LogLevel level) { _logger = logger; _level = level; @@ -29,7 +29,7 @@ internal EnabledLogLevel([NotNull] ILogger logger, LogLevel level) /// /// Message template. /// Template parameters. - public void Log([NotNull] string message, [CanBeNull] params object[] args) + public void Log(string message, params object[]? args) { // ReSharper disable once TemplateIsNotCompileTimeConstantProblem _logger.Log(_level, message, args); @@ -41,7 +41,7 @@ public void Log([NotNull] string message, [CanBeNull] params object[] args) /// Exception to log. /// Message template. /// Template parameters. - public void Log([CanBeNull] Exception ex, [NotNull] string message, [CanBeNull] params object[] args) + public void Log(Exception? ex, string message, params object[]? args) { // ReSharper disable once TemplateIsNotCompileTimeConstantProblem _logger.Log(_level, ex, message, args); diff --git a/Src/SharpArch.Infrastructure/Logging/EnabledLogger.cs b/Src/SharpArch.Infrastructure/Logging/EnabledLogger.cs index dca75efec..3208a8300 100644 --- a/Src/SharpArch.Infrastructure/Logging/EnabledLogger.cs +++ b/Src/SharpArch.Infrastructure/Logging/EnabledLogger.cs @@ -10,13 +10,13 @@ namespace SharpArch.Infrastructure.Logging /// public readonly struct LogWrapper { - [NotNull] readonly ILogger _logger; + readonly ILogger _logger; /// /// Constructor. /// /// Logger. - public LogWrapper([NotNull] ILogger logger) + public LogWrapper(ILogger logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } diff --git a/Src/SharpArch.NHibernate.DependencyInjection/NHibernateRegistrationExtensions.cs b/Src/SharpArch.NHibernate.DependencyInjection/NHibernateRegistrationExtensions.cs index 8a1cbce08..0ec846274 100644 --- a/Src/SharpArch.NHibernate.DependencyInjection/NHibernateRegistrationExtensions.cs +++ b/Src/SharpArch.NHibernate.DependencyInjection/NHibernateRegistrationExtensions.cs @@ -97,7 +97,7 @@ public static IServiceCollection AddNHibernateWithSingleDatabase( return services; } - static LogWrapper GetLogger([NotNull] IServiceProvider sp) + static LogWrapper GetLogger(IServiceProvider sp) { var logger = new LogWrapper(sp.GetRequiredService() .CreateLogger("SharpArch.NHibernate.Extensions.DependencyInjection")); diff --git a/Src/SharpArch.NHibernate/FluentNHibernate/IAutoPersistenceModelGenerator.cs b/Src/SharpArch.NHibernate/FluentNHibernate/IAutoPersistenceModelGenerator.cs index 232d6710d..34b7335fe 100644 --- a/Src/SharpArch.NHibernate/FluentNHibernate/IAutoPersistenceModelGenerator.cs +++ b/Src/SharpArch.NHibernate/FluentNHibernate/IAutoPersistenceModelGenerator.cs @@ -17,7 +17,7 @@ public interface IAutoPersistenceModelGenerator /// /// Generates persistence model. /// - [NotNull] + AutoPersistenceModel Generate(); } } diff --git a/Src/SharpArch.NHibernate/FluentNHibernate/IMapGenerator.cs b/Src/SharpArch.NHibernate/FluentNHibernate/IMapGenerator.cs index cae2e1db7..5f1d76365 100644 --- a/Src/SharpArch.NHibernate/FluentNHibernate/IMapGenerator.cs +++ b/Src/SharpArch.NHibernate/FluentNHibernate/IMapGenerator.cs @@ -25,7 +25,7 @@ public interface IMapGenerator /// /// Generates XML mapping document. /// - [NotNull] + XmlDocument Generate(); } } diff --git a/Src/SharpArch.NHibernate/ISessionFactoryKeyProvider.cs b/Src/SharpArch.NHibernate/ISessionFactoryKeyProvider.cs index d6237cf2d..88f3569b6 100644 --- a/Src/SharpArch.NHibernate/ISessionFactoryKeyProvider.cs +++ b/Src/SharpArch.NHibernate/ISessionFactoryKeyProvider.cs @@ -13,7 +13,7 @@ public interface ISessionFactoryKeyProvider /// Gets the session factory key. /// /// - [NotNull] + string GetKey(); /// @@ -21,7 +21,7 @@ public interface ISessionFactoryKeyProvider /// /// An optional object that may have an attribute used to determine the session factory key. /// - [NotNull] - string GetKeyFrom([NotNull] object anObject); + + string GetKeyFrom(object anObject); } } \ No newline at end of file diff --git a/Src/SharpArch.NHibernate/NHibernateQuery.cs b/Src/SharpArch.NHibernate/NHibernateQuery.cs index 0d5d0d9e3..0093d5a22 100644 --- a/Src/SharpArch.NHibernate/NHibernateQuery.cs +++ b/Src/SharpArch.NHibernate/NHibernateQuery.cs @@ -15,7 +15,7 @@ public abstract class NHibernateQuery /// /// The session. /// is null. - protected NHibernateQuery([NotNull] ISession session) + protected NHibernateQuery(ISession session) { if (session == null) throw new ArgumentNullException(nameof(session)); @@ -25,7 +25,7 @@ protected NHibernateQuery([NotNull] ISession session) /// /// NHibernate . /// - [NotNull] + protected virtual ISession Session { get; } } } diff --git a/Src/SharpArch.NHibernate/NHibernateRepositoryBase.cs b/Src/SharpArch.NHibernate/NHibernateRepositoryBase.cs index 81419bf94..12d4b5002 100644 --- a/Src/SharpArch.NHibernate/NHibernateRepositoryBase.cs +++ b/Src/SharpArch.NHibernate/NHibernateRepositoryBase.cs @@ -26,7 +26,7 @@ public class NHibernateRepository : INHibernateRepository /// Gets NHibernate session. /// - [NotNull] + protected ISession Session => TransactionManager.Session; /// @@ -34,7 +34,7 @@ public class NHibernateRepository : INHibernateRepository - [NotNull] + protected INHibernateTransactionManager TransactionManager { get; } /// @@ -43,7 +43,7 @@ public class NHibernateRepository : INHibernateRepositoryThe transaction manager. /// public NHibernateRepository( - [NotNull] INHibernateTransactionManager transactionManager) + INHibernateTransactionManager transactionManager) { TransactionManager = transactionManager ?? throw new ArgumentNullException(nameof(transactionManager)); } @@ -177,7 +177,7 @@ public virtual async Task UpdateAsync(TEntity entity, CancellationToken /// This is provided to facilitate developing the domain layer without a direct dependency on the /// NHibernate assembly. /// - [NotNull] static LockMode ConvertFrom(Enums.LockMode lockMode) + static LockMode ConvertFrom(Enums.LockMode lockMode) => lockMode switch { Enums.LockMode.None => LockMode.None, diff --git a/Src/SharpArch.NHibernate/NHibernateSessionFactoryBuilder.cs b/Src/SharpArch.NHibernate/NHibernateSessionFactoryBuilder.cs index ea2beb693..e7035a005 100644 --- a/Src/SharpArch.NHibernate/NHibernateSessionFactoryBuilder.cs +++ b/Src/SharpArch.NHibernate/NHibernateSessionFactoryBuilder.cs @@ -81,7 +81,7 @@ public Configuration BuildConfiguration() /// Changes to configuration will be persisted in configuration cache, if it is enabled. /// In case changes must not be persisted in cache, they must be applied after . /// - public NHibernateSessionFactoryBuilder ExposeConfiguration([NotNull] Action config) + public NHibernateSessionFactoryBuilder ExposeConfiguration(Action config) { _exposeConfiguration = config ?? throw new ArgumentNullException(nameof(config)); return this; @@ -99,8 +99,8 @@ bool ShouldExposeConfiguration() /// The mapping assemblies. /// /// Mapping assemblies are not specified. - [NotNull] - public NHibernateSessionFactoryBuilder AddMappingAssemblies([NotNull] IEnumerable mappingAssemblies) + + public NHibernateSessionFactoryBuilder AddMappingAssemblies(IEnumerable mappingAssemblies) { if (mappingAssemblies == null) throw new ArgumentNullException(nameof(mappingAssemblies), "Mapping assemblies are not specified."); @@ -115,9 +115,9 @@ public NHibernateSessionFactoryBuilder AddMappingAssemblies([NotNull] IEnumerabl /// The automatic persistence model. /// /// - [NotNull] + public NHibernateSessionFactoryBuilder UseAutoPersistenceModel( - [NotNull] AutoPersistenceModel autoPersistenceModel) + AutoPersistenceModel autoPersistenceModel) { _autoPersistenceModel = autoPersistenceModel ?? throw new ArgumentNullException(nameof(autoPersistenceModel)); return this; @@ -130,8 +130,8 @@ public NHibernateSessionFactoryBuilder UseAutoPersistenceModel( /// The properties. /// Builder instance. /// is null. - [NotNull] - public NHibernateSessionFactoryBuilder UseProperties([NotNull] IEnumerable> properties) + + public NHibernateSessionFactoryBuilder UseProperties(IEnumerable> properties) { if (properties == null) throw new ArgumentNullException(nameof(properties)); @@ -152,7 +152,7 @@ public NHibernateSessionFactoryBuilder UseProperties([NotNull] IEnumerable /// . - [NotNull] + public NHibernateSessionFactoryBuilder UseDataAnnotationValidators(bool addDataAnnotationValidators) { _useDataAnnotationValidators = addDataAnnotationValidators; @@ -167,7 +167,7 @@ public NHibernateSessionFactoryBuilder UseDataAnnotationValidators(bool addDataA /// details /// /// NHibernate config was not specified. - [NotNull] + public NHibernateSessionFactoryBuilder UseConfigFile(string nhibernateConfigFile) { if (string.IsNullOrWhiteSpace(nhibernateConfigFile)) @@ -182,8 +182,8 @@ public NHibernateSessionFactoryBuilder UseConfigFile(string nhibernateConfigFile /// Allows to configure second-level cache. /// /// Cache settings configuration. Use null to clear previous setting. - [NotNull] - public NHibernateSessionFactoryBuilder UseCache([CanBeNull] Action cacheSettingsBuilder) + + public NHibernateSessionFactoryBuilder UseCache(Action? cacheSettingsBuilder) { _cacheSettingsBuilder = cacheSettingsBuilder; return this; @@ -202,9 +202,9 @@ public NHibernateSessionFactoryBuilder UseCache([CanBeNull] Action /// /// is null. - [NotNull] + public NHibernateSessionFactoryBuilder UsePersistenceConfigurer( - [NotNull] IPersistenceConfigurer persistenceConfigurer) + IPersistenceConfigurer persistenceConfigurer) { _persistenceConfigurer = persistenceConfigurer ?? throw new ArgumentNullException(nameof(persistenceConfigurer)); return this; diff --git a/Src/SharpArch.NHibernate/SessionExtensions.cs b/Src/SharpArch.NHibernate/SessionExtensions.cs index a4cd5d5bf..5d6645fd7 100644 --- a/Src/SharpArch.NHibernate/SessionExtensions.cs +++ b/Src/SharpArch.NHibernate/SessionExtensions.cs @@ -23,7 +23,7 @@ public static class SessionExtensions /// or is /// null. /// - public static void FlushAndEvict([NotNull] this ISession session, [NotNull] object entity) + public static void FlushAndEvict(this ISession session, object entity) { if (session == null) throw new ArgumentNullException(nameof(session)); if (entity == null) throw new ArgumentNullException(nameof(entity)); @@ -44,7 +44,7 @@ public static void FlushAndEvict([NotNull] this ISession session, [NotNull] obje /// /// or is null. /// - public static async Task FlushAndEvictAsync([NotNull] this ISession session, [NotNull] object entity, CancellationToken cancellationToken) + public static async Task FlushAndEvictAsync(this ISession session, object entity, CancellationToken cancellationToken) { if (session == null) throw new ArgumentNullException(nameof(session)); if (entity == null) throw new ArgumentNullException(nameof(entity)); @@ -65,7 +65,7 @@ public static async Task FlushAndEvictAsync([NotNull] this ISession session, [No /// Entity to increment version for. /// Cancellation token /// is null. - public static Task IncrementVersionAsync([NotNull] this ISession session, [CanBeNull] object entity, CancellationToken cancellationToken) + public static Task IncrementVersionAsync(this ISession session, object? entity, CancellationToken cancellationToken) { if (session == null) throw new ArgumentNullException(nameof(session)); if (entity == null) return Task.CompletedTask; @@ -84,7 +84,7 @@ public static Task IncrementVersionAsync([NotNull] this ISession session, [CanBe /// /// Entity to increment version for. /// is null. - public static void IncrementVersion([NotNull] this ISession session, [CanBeNull] object entity) + public static void IncrementVersion(this ISession session, object? entity) { if (session == null) throw new ArgumentNullException(nameof(session)); if (entity == null) return; @@ -106,7 +106,7 @@ public static void IncrementVersion([NotNull] this ISession session, [CanBeNull] /// /// or is null. /// - public static bool IsModified([NotNull] this ISession session, [NotNull] object entity) + public static bool IsModified(this ISession session, object entity) { if (session == null) throw new ArgumentNullException(nameof(session)); if (entity == null) throw new ArgumentNullException(nameof(entity)); diff --git a/Src/SharpArch.NHibernate/TransactionManager.cs b/Src/SharpArch.NHibernate/TransactionManager.cs index a807d8a0a..1c98deab9 100644 --- a/Src/SharpArch.NHibernate/TransactionManager.cs +++ b/Src/SharpArch.NHibernate/TransactionManager.cs @@ -21,7 +21,7 @@ public class TransactionManager : INHibernateTransactionManager, ISupportsTransa /// Creates instance of transaction manager. /// /// - public TransactionManager([NotNull] ISession session) + public TransactionManager(ISession session) { Session = session ?? throw new ArgumentNullException(nameof(session)); } diff --git a/Src/SharpArch.Testing.Xunit.NHibernate/TransientDatabaseTests.cs b/Src/SharpArch.Testing.Xunit.NHibernate/TransientDatabaseTests.cs index b8d156403..8ae5ca7b1 100644 --- a/Src/SharpArch.Testing.Xunit.NHibernate/TransientDatabaseTests.cs +++ b/Src/SharpArch.Testing.Xunit.NHibernate/TransientDatabaseTests.cs @@ -29,26 +29,26 @@ public abstract class TransientDatabaseTests : IClassFixture /// Transaction manager. /// - [NotNull] + protected TransactionManager TransactionManager { get; private set; } /// /// Database initializer. /// - [NotNull] + protected TestDatabaseSetup DbSetup { get; private set; } /// /// Database session. /// - [NotNull] + protected ISession Session => TransactionManager.Session; /// /// Constructor. /// /// - protected TransientDatabaseTests([NotNull] TestDatabaseSetup dbSetup) + protected TransientDatabaseTests(TestDatabaseSetup dbSetup) { DbSetup = dbSetup ?? throw new ArgumentNullException(nameof(dbSetup)); TransactionManager = new TransactionManager(DbSetup.InitializeSession()); @@ -74,8 +74,8 @@ public virtual void Dispose() /// The entity instance. /// Cancellation token. /// is - [NotNull] - protected Task FlushSessionAndEvict([NotNull] object instance, CancellationToken cancellationToken = default) + + protected Task FlushSessionAndEvict(object instance, CancellationToken cancellationToken = default) => Session.FlushAndEvictAsync(instance, cancellationToken); /// @@ -84,7 +84,7 @@ protected Task FlushSessionAndEvict([NotNull] object instance, CancellationToken /// The entity instance. /// Cancellation token. /// is - protected async Task SaveAndEvict([NotNull] object instance, CancellationToken cancellationToken = default) + protected async Task SaveAndEvict(object instance, CancellationToken cancellationToken = default) { if (instance == null) throw new ArgumentNullException(nameof(instance)); await Session.SaveAsync(instance, cancellationToken).ConfigureAwait(false); @@ -94,7 +94,7 @@ protected async Task SaveAndEvict([NotNull] object instance, CancellationToken c /// /// Initializes database before each test run. /// - [NotNull] + protected abstract Task LoadTestData(CancellationToken cancellationToken); } } From b1c6491de4ef568015749aa7c612cf54ad8312e5 Mon Sep 17 00:00:00 2001 From: vk Date: Sun, 11 Apr 2021 22:31:26 -0400 Subject: [PATCH 12/13] Session configuration hooks for in database tests, closes #244 --- SharpArch.AutoLoad.DotSettings | 4 ++ Src/Common/NHibernate/TestDatabaseSetup.cs | 62 +++++++++++++++++-- .../Logging/EnabledLogLevel.cs | 1 + .../Logging/EnabledLogger.cs | 1 + 4 files changed, 64 insertions(+), 4 deletions(-) diff --git a/SharpArch.AutoLoad.DotSettings b/SharpArch.AutoLoad.DotSettings index 4a9b488b3..5706dde30 100644 --- a/SharpArch.AutoLoad.DotSettings +++ b/SharpArch.AutoLoad.DotSettings @@ -95,7 +95,11 @@ FluentAssertions.AssertionExtensions.Should($EXPR$).NotBeNull() 150 CHOP_ALWAYS 1 + 2 100 + 2 + False + 140 <?xml version="1.0" encoding="utf-16"?> <Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"> <TypePattern DisplayName="Non-reorderable types"> diff --git a/Src/Common/NHibernate/TestDatabaseSetup.cs b/Src/Common/NHibernate/TestDatabaseSetup.cs index 64f1af843..d1cc36392 100644 --- a/Src/Common/NHibernate/TestDatabaseSetup.cs +++ b/Src/Common/NHibernate/TestDatabaseSetup.cs @@ -1,6 +1,7 @@ namespace SharpArch.Testing.NHibernate { using System; + using System.Data.Common; using System.Diagnostics; using System.IO; using System.Linq; @@ -66,6 +67,22 @@ public TestDatabaseSetup(Assembly baseAssembly, Assembly[] mappingAssemblies) { } + /// + /// Allows to apply custom configuration to new ISession. + /// + /// + /// Callback is executed by default implementation of from . + /// + public Action? SessionConfigurator { get; set; } + + /// + /// Allows to apply custom configuration to new ISession. + /// + /// + /// Callback is executed by default implementation of from . + /// + public Action? StatelessSessionConfigurator { get; set; } + /// /// Disposes SessionFactory. /// @@ -163,11 +180,32 @@ protected virtual void Customize(NHibernateSessionFactoryBuilder builder) { } + /// + /// Configures before usage. + /// + /// Session builder. + protected virtual ISessionBuilder ConfigureSession(ISessionBuilder sessionBuilder) + { + if (sessionBuilder == null) throw new ArgumentNullException(nameof(sessionBuilder)); + SessionConfigurator?.Invoke(sessionBuilder); + return sessionBuilder; + } + + /// + /// Configures before usage. + /// + /// Session builder. + protected virtual IStatelessSessionBuilder ConfigureStatelessSession(IStatelessSessionBuilder statelessSessionBuilder) + { + if (statelessSessionBuilder == null) throw new ArgumentNullException(nameof(statelessSessionBuilder)); + StatelessSessionConfigurator?.Invoke(statelessSessionBuilder); + return statelessSessionBuilder; + } + /// /// Returns NHibernate . /// Session factory instance is cached, all subsequent calls to GetSessionFactory() will return the same instance. /// - public ISessionFactory GetSessionFactory() { if (_sessionFactory != null) return _sessionFactory; @@ -179,16 +217,32 @@ public ISessionFactory GetSessionFactory() /// Creates new NHibernate session and initializes database structure. /// /// NHibernate Session - public ISession InitializeSession() { - var session = GetSessionFactory().OpenSession(); + var sessionBuilder = GetSessionFactory().WithOptions(); + var session = ConfigureSession(sessionBuilder).OpenSession(); var connection = session.Connection; new SchemaExport(_configuration).Execute(false, true, false, connection, null); - return session; } + /// + /// Creates new NHibernate stateless session. + /// + /// + /// When testing using transient database, database structure should be created once per test. + /// If stateless session is required, it should be created using connection opened by regular session, . + /// + /// NHibernate Session + public IStatelessSession CreateStatelessSessionForConnection(DbConnection connection) + { + if (connection == null) throw new ArgumentNullException(nameof(connection)); + var sessionBuilder = GetSessionFactory().WithStatelessOptions(); + sessionBuilder.Connection(connection); + var statelessSession = ConfigureStatelessSession(sessionBuilder).OpenStatelessSession(); + return statelessSession; + } + /// /// Closes the specified session. /// diff --git a/Src/SharpArch.Infrastructure/Logging/EnabledLogLevel.cs b/Src/SharpArch.Infrastructure/Logging/EnabledLogLevel.cs index 4453087a4..68f40975b 100644 --- a/Src/SharpArch.Infrastructure/Logging/EnabledLogLevel.cs +++ b/Src/SharpArch.Infrastructure/Logging/EnabledLogLevel.cs @@ -8,6 +8,7 @@ namespace SharpArch.Infrastructure.Logging /// /// Logs with specific log level. /// + [PublicAPI] public readonly struct EnabledLogLevel { readonly ILogger _logger; diff --git a/Src/SharpArch.Infrastructure/Logging/EnabledLogger.cs b/Src/SharpArch.Infrastructure/Logging/EnabledLogger.cs index 3208a8300..37c9749d0 100644 --- a/Src/SharpArch.Infrastructure/Logging/EnabledLogger.cs +++ b/Src/SharpArch.Infrastructure/Logging/EnabledLogger.cs @@ -8,6 +8,7 @@ namespace SharpArch.Infrastructure.Logging /// /// Skips call to to prevent unnecessary memory allocations. /// + [PublicAPI] public readonly struct LogWrapper { readonly ILogger _logger; From 90b35b4cee208a9664c20adc007ad20bc9bc2d82 Mon Sep 17 00:00:00 2001 From: vk Date: Mon, 31 May 2021 12:25:51 -0400 Subject: [PATCH 13/13] Update VersionHistory --- VersionHistory.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/VersionHistory.txt b/VersionHistory.txt index d69fee63d..55fc1b40b 100644 --- a/VersionHistory.txt +++ b/VersionHistory.txt @@ -2,6 +2,9 @@ vNext ======================== +S#arp 7.0.0 +======================== + BREAKING: * Removed EntityWithTypedId<> replaced with Entity<>, removed old entity class. Fix: replace `Entity` with `Entity`. * Renamed IAsyncRepository to IRepository.